LINUX.ORG.RU

Один бинарник на четыре системы

 , , , ,


8

1

Это текстовая версия статьи, оригинал с картинками вот тут

Все что мы делаем — отражается эхом в вечности, надеюсь что меня запомнят по этой работе, ибо творил я во славу ультрахардкора.

This is Spartaaa!

Обычные программы либо компилируются под какую-то конкретную ОС и архитектуру процессора, либо же требуют специальное окружение для запуска и работы. Которое еще нужно скачать и установить.

Это — норма и для коммерческого софта лучше так и делать впредь. Хоть это и серо, скучно и уныло.

То что я покажу ниже в этой статье — «Proof of Concept» (PoC), доказательство что сделать единый запускаемый бинарник под четыре абсолютно разные и несовместимые платформы технически возможно.

Как это выглядит

Один исполняемый файл all.cmd без изменений, без перекомпиляции и сборок запускается «as-is» на Windows, Linux, FreeBSD и MacOS. Запускается именно в пользовательском смысле: по клику, по нажатию Enter, через ./all.cmd — так как запускается обычная родная программа в каждой конкретной ОС. Без дополнительных действий, без каких-то параметров запуска, без всего. Вообщем, по хардкору.

Как это работает

Шелл-скрипт упаковывается вместе с бинарником в один файл. Скрипт — в начале файла, бинарник с приложением — в конце. Сама по себе технология известная. но у меня получилось развить ее несколько дальше:

Я использовал приложение на Java в качестве бинарника, но тоже самое можно реализовать и с дотнетом и с Python-приложением.

Jar файл, в который упаковывается Java-приложение является ZIP-архивом, особенностью формата которого является то, что процесс чтения начинается с конца файла.

А вот шелл-скрипт как и Windows Batch выполняется пошагово с начала файла. Это и позволяет сделать запуск «себя самого»:

self=`(readlink -f $0)`
java -jar $self 
exit

Проблема Windows

Microsoft как известно всегда идет своим путем, который затем навязывает окружающим. И их командный интерпретатор не стал исключением. Не думал, что вообще возможно сделать чтобы один и тот же скрипт выполнился как в Windows Batch так и в обычном bash. Но как ни странно решение нашлось. Скелет скрипта, который отрабатывает и в Windows и в bash вот:

rem(){ :;};rem '
@goto b
';echo Starting Demo..;

:b
@echo off
@echo Starting Demo...

Работает это за счет пересечения синтаксиса из двух миров: для Windows Batch rem это функция пропуска строки, те все что начинается со слова rem полностью пропускается вендовым интерпретатором. А вот для bash rem() это определение пустой функции и ее немедленный вызов с мультистрокой:

rem '
@goto b
';

Те фактически bash этот блок пропустит. А вот вендовый cmd.exe сделает переход по метке:

@goto b

В блок, где начинается уже полноценный код для Windows Batch:

:b
@echo off
@echo Starting Demo...

Вот таким чудным образом получается единая точка запуска для всего. И никакой магии.

Определение окружения

Чтобы запустить приложение на Java нужен рантайм — JRE, которого на машине может и не быть, либо он может быть устаревшей версии. Поэтому для полной радости, я добавил проверку версии и автоматическое скачивание JRE для Windows и Linux платформ. Для Linux учитывается тип архитектуры. Общая логика для Linux, FreeBSD и MacOS выглядит вот так:

echo "1. Searching for Java JRE.."
if type -p java; then
    echo "1.1 Found Java executable in PATH"
    _JRE=java
elif [[ -n $JAVA_HOME ]] && [[ -x "$JAVA_HOME/bin/java" ]];  then
    echo "1.2 Found Java executable in JAVA_HOME"
    _JRE="$JAVA_HOME/bin/java"
else
    echo "1.3 no JRE found"    
fi

v="$(jdk_version)"
echo "2. Detected Java version: $v"
if [[ $v -lt 8 ]]
then
    echo "2.1 Found unsupported version: $v"
    try_download_java
    echo "2.2 Using JRE: $_JRE"
fi
self=`(readlink -f $0)`
$_JRE -jar $self
exit

Сначала мы ищем «java» в виде команды, доступной из окружения. Если не нашли — проверяем наличие переменной JAVA_HOME в окружении (в этой переменной указывается обычно путь до JDK) Дальше проверяем версию найденной Java:

# returns the JDK version.
# 8 for 1.8.0_nn, 9 for 9-ea etc, and "no_java" for undetected
jdk_version() {
  local result
  local java_cmd
  if [[ -n $(type -p java) ]]
  then
    java_cmd=java
  elif [[ (-n "$JAVA_HOME") && (-x "$JAVA_HOME/bin/java") ]]
  then
    java_cmd="$JAVA_HOME/bin/java"
  fi
  local IFS=#x27;\n'
  # remove \r for Cygwin
  local lines=$("$java_cmd" -Xms32M -Xmx32M -version 2>&1 | tr '\r' '\n')
  if [[ -z $java_cmd ]]
  then
    result=no_java
  else
    for line in $lines; do
      if [[ (-z $result) && ($line = *"version \""*) ]]
      then
        local ver=$(echo $line | sed -e 's/.*version "\(.*\)"\(.*\)/\1/; 1q')
        # on macOS, sed doesn't support '?'
        if [[ $ver = "1."* ]]
        then
          result=$(echo $ver | sed -e 's/1\.\([0-9]*\)\(.*\)/\1/; 1q')
        else
          result=$(echo $ver | sed -e 's/\([0-9]*\)\(.*\)/\1/; 1q')
        fi
      fi
    done
  fi
  echo "$result"
}

Суть в том чтобы получить одно число, соответствующее мажорной версии найденной JRE: 8 — для Java 1.8, 9 — для Java 9, 11,14,19 и так далее. Эта функция вызывается, затем проверяется полученное число версии:

v="$(jdk_version)"
echo "2. Detected Java version: $v"
if [[ $v -lt 8 ]]
then
    echo "2.1 Found unsupported version: $v"
    try_download_java
    echo "2.2 Using JRE: $_JRE"
fi

Если найденная JRE слишком старая - пытаемся скачать. Но сначала проверяем есть ли уже скачанная версия:

UNPACKED_JRE=~/.jre/jre
if [[ -f "$UNPACKED_JRE/bin/java" ]]; then
    echo "3.1 Found unpacked JRE"
    _JRE="$UNPACKED_JRE/bin/java"
    return 0
fi

Вот так выглядит определение типа архитектуры и сопоставление части имени файла со скачиваемым JRE:

# Detect the platform (similar to $OSTYPE)
OS="`uname`"
ARCH="`uname -m`"
# select correct path segments based on CPU architecture and OS
case $ARCH in
   'x86_64')
     ARCH='x64'
     ;;
    'i686')
     ARCH='i586'
     ;;
    *)
    exit_error "Unsupported for automatic download"
     ;;
esac

Обратите внимание что 32битная система с линуксом будет называть себя i686, а в названии 32битной JRE будет i586. К сожалению бинарных сборок в виде скачиваемого архива для FreeBSD и MacOS нет, поэтому пока вот так:

case $OS in
  'Linux')
    OS='linux'
    ;;
  *)
    exit_error "Unsupported for automatic download"
     ;;
esac

Эти параметры затем подставляются в полную ссылку для скачивания:

echo "3.2 Downloading for OS: $OS and arch: $ARCH"
URL="https://../../jvm/com/oracle/jre/1.8.121/jre-1.8.121-$OS-$ARCH.zip"
echo "Full url: $URL"

Откуда берется JRE

Вообще Oracle не дает скачивать релизы JRE в автоматическом режиме, поэтому для тестов выложили бинарные сборки OpenJDK и JRE в виде зависимостей Maven, вот тут. Это устаревшая 1.8 версия, но для PoC прототипа хватит. Ниже опишу логику работы скрипта. Вот так происходит скачивание и распаковка:

echo "Full url: $URL"
CODE=$(curl -L -w '%{http_code}' -o /tmp/jre.zip -C - $URL)
if [[ "$CODE" =~ ^2 ]]; then
    # Server returned 2xx response
    mkdir -p ~/.jre
    unzip /tmp/jre.zip -d ~/.jre/
    _JRE="$UNPACKED_JRE/bin/java"
    return 0
elif [[ "$CODE" = 404 ]]; then
    exit_error "3.3 Unable to download JRE from $URL"
else
    exit_error "3.4 ERROR: server returned HTTP code $CODE"
fi

По идее нужно еще отдельно проверять возвращаемые коды при создании каталога и распаковке — но для PoC думаю и текущей логики хватит.

Часть с Windows

Теперь детально разберем часть скрипта, отвечающего за венду. Вот отсюда она начинается:

:b
@echo off
@echo Starting Demo...
:: self script name
set SELF_SCRIPT=%0

Первым делом сохраняем полный путь до себя самого (%0) в переменную SELF_SCRIPT, тк дальше он может быть перезаписан. Дальше определяем путь до распакованной JRE, которая будет храниться в домашней папке текущего пользователя:

:: path to unpacked JRE
set UNPACKED_JRE_DIR=%UserProfile%\.jre
:: path to unpacked JRE binary
set UNPACKED_JRE=%UNPACKED_JRE_DIR%\jre\bin\javaw.exe

IF exist %UNPACKED_JRE% (goto :RunJavaUnpacked)

Если бинарник JRE существует — считаем что JRE уже был скачан и используем его. Обратите внимание на особенность вендов, в виде отдельного бинарника для графических приложений: javaw.exe Если скачанного JRE нет — пытаемся найти в окружении. Если нашли — пытаемся определить версию:

where javaw 2>NUL
if "%ERRORLEVEL%"=="0" (call :JavaFound) else (call :NoJava)
goto :EOF
:JavaFound
set JRE=javaw
echo Java found in PATH, checking version..
set JAVA_VERSION=0
for /f "tokens=3" %%g in ('java -version 2^>^&1 ^| findstr /i "version"') do (
  set JAVA_VERSION=%%g
)
set JAVA_VERSION=%JAVA_VERSION:"=%
for /f "delims=.-_ tokens=1-2" %%v in ("%JAVA_VERSION%") do (
  if /I "%%v" EQU "1" (
    set JAVA_VERSION=%%w
  ) else (
    set JAVA_VERSION=%%v
  )
)

Считаем, что если есть javaw.exe то есть и java.exe, поскольку в вендовых сборках оба бинарника обязательно присутствуют в папке bin. Общий смысл кода выше ровно такой же что и для bash версии - получить мажорную цифру версии JRE для последующей проверки: if %JAVA_VERSION% LSS 8 (goto :DownloadJava) else (goto :RunJava) Если найденная JRE старше 1.8 — считаем что она не поддерживается и пытаемся скачать. Вот так выглядит скачивание и распаковка JRE:

:DownloadJava
echo JRE not found in PATH, trying to download..
WHERE curl
IF %ERRORLEVEL% NEQ 0 (call :ExitError "curl wasn't found in PATH, cannot download JRE") 
WHERE tar
IF %ERRORLEVEL% NEQ 0 (call :ExitError "tar wasn't found in PATH, cannot download JRE")  
curl.exe -o %TEMP%\jre.zip  -C - https://nexus.nuiton.org/nexus/content/repositories/jvm/com/oracle/jre/1.8.121/jre-1.8.121-windows-i586.zip
IF not exist %UNPACKED_JRE_DIR% (mkdir %UNPACKED_JRE_DIR%)
tar -xf %TEMP%\jre.zip -C %UNPACKED_JRE_DIR%

Важные моменты:

Глаза вам не врут: curl и tar теперь действительно есть в Windows. На самом деле аж с 2017 года.
Используем одну универсальную 32х битную версию JRE, без учета архитектуры, поскольку на Windows нет проблемы совместимости и запуска 32х битных приложений на x86_64 архитектуре. Ну и это все же PoC для тестирования а не жирный продакшн. Код запуска выглядит вот так:

:RunJavaUnpacked
set JRE=%UNPACKED_JRE_DIR%\jre\bin\javaw.exe
:RunJava
echo Using JRE %JAVA_VERSION% from %JRE%
start %JRE% -jar %SELF_SCRIPT%
goto :EOF
:ExitError
echo Found Error: %0
pause
:EOF
exit
Тут необходимо пояснить про ссылочную логику и метки. Команда goto делает переход в место скрипта отмеченное меткой:
goto :EOF
перейдет вот сюда, минуя весь остальной код:
:EOF
exit

А если метки нет то выполнение продолжится последовательно, поэтому после:

set JRE=%UNPACKED_JRE_DIR%\jre\bin\javaw.exe

выполнится:

echo Using JRE %JAVA_VERSION% from %JRE%

И дальше до конца.

MacOS и readlink

Оказалось что реализация readlink на маке не поддерживает ключ -f ,несмотря на все визги про то что MacOS это тоже BSD. Поэтому пришлось добавлять реализацию прямо в скрипт:

# Return the canonicalized path (works on OS-X like 'readlink -f' on Linux); . is $PWD
function get_realpath {
    [ "." = "${1}" ] && n=${PWD} || n=${1}; while nn=$( readlink -n "$n" ); do n=$nn; done; echo "$n"
}

Эта функция используется для вычисления собственного полного пути, с учетом ссылок и относительных частей. Шелл по-умолчанию В MacOS начиная с Catalina по-умолчанию используется zsh, в FreeBSD - ksh а в большинстве линуксов - bash. Код загрузчика для юниксов в этом проекте написан для bash.

Чтобы автоматически перезапустить скрипт через bash, если пользователь запускает другим интерпретатором, используется вот такой код:

if [ -z "$BASH" ]; then 
echo "0. Current shell is not bash. Trying to re-run with bash.." 
exec bash $0
exit
fi

Тестовый проект

Весь проект выложен на Github вот тут. Имейте ввиду что две части шелл-скрипта - для Windows Batch и для bash имеют разную настройку окончания строк! Это оказалось обязательным для запуска на MacOS. Само тестовое приложение на Swing, примечательно циклом сборки. Я использовал BeanShell plugin, для того чтобы реализовать логику упаковки в виде inline-скрипта на самой Java:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.Ox08.experiments</groupId>
    <artifactId>full-cross</artifactId>
    <version>1.0-RELEASE</version>
    <name>0x08 Experiments: Full Cross Application</name>
    <packaging>jar</packaging>
    <url>https://teletype.in/@alex0x08</url>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <exec.mainClass>com.ox08.demos.fullcross.FullCross</exec.mainClass>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.3.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.ox08.demos.fullcross.FullCross</mainClass>
                        </manifest>                       
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>com.github.genthaler</groupId>
                <artifactId>beanshell-maven-plugin</artifactId>
                <version>1.4</version>                
                <executions>
               <execution>
                  <phase>package</phase>
                  <goals>
                     <goal>run</goal>
                  </goals>
               </execution>
            </executions>
                <configuration>
                    <quiet>true</quiet>                
                    <script>
                <![CDATA[
                        import java.io.*; 
                        // function should be defined before actual call
                        // this just appends source binary to target
                         void copy(File src,OutputStream fout) {
                            FileInputStream fin = null;
                            try {    
                            fin =new FileInputStream(src);                         
                            byte[] b = new byte[1024];
                            int noOfBytes = 0; 
                            while( (noOfBytes = fin.read(b)) != -1 )
                            { fout.write(b, 0, noOfBytes);  } 
                            } catch (Exception e) {
                                e.printStackTrace();
                            } finally {
                                fout.flush();
                                if (fin!=null) { fin.close(); }
                            }                             
                        }                  
                        // current project folder                                           
                        String projectDir = System.getProperty("maven.multiModuleProjectDirectory");
                        // target combined binary
                        File target = new File(projectDir+"/target/all.cmd");    
                        if (target.exists()) {
                            target.delete();
                        }            
                        // shell bootloader
                        File fboot = new File(projectDir+"/src/main/cmd/boot.cmd");                
                        // jar file with application    
                        File fjar = new File(projectDir+"/target/full-cross-1.0-RELEASE.jar");                
                        // open write stream to target combined binary
                        FileOutputStream fout = new FileOutputStream(target);
                        // write bootloader
                        copy(fboot,fout);
                        // write jar
                        copy(fjar,fout);
                        fout.close();
                        target.setExecutable(true);
                ]]>
                    </script>
                </configuration>                
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-install-plugin</artifactId>
                <version>3.1.1</version>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
          </plugins>
    </build>
</project>

Собирается абсолютно любой JDK cтарше 1.8 версии:

mvn clean package

Можно использовать внешний Apache Maven, либо собрать из любой среды разработки. Итоговый бинарник будет в папке target.

Нехорошие дела

Полагаю у некоторых читателей далеких от ИБ, появилась мысль о возможности нехорошего применения этой технологии: сваять какую-нибудь кроссплатформенную малварь/шифровальщик/вирь и все в этом духе.

На самом деле так заморачиваться никому не интересно - объем кода, который делает эскалацию привилегий в системе, открывает бекдор или творит еще какую дичь и так немаленький. Тащить три разных версии такого кода, под разные ОС, с собой в одном бинарнике - ну совсем перебор.

Второй важный момент - командный интерпретатор выполняется пошагово, там нет тредов, поэтому весь код отлично просматривается любыми антивирусами, даже самыми тупыми. Вообщем не интересно это нормальным бандитам.

Выводы

В принципе Америку я не открыл - такое известно давно и давно используется на практике. Вот тут находится огромная статья с примерами на разных языках.

Вот тут находится проект для создания кросс-платформенных самораспаковывающихся архивов под разные типы Unix, используется та же идея.

Тем не менее, полную сборку в готовое решение, с кроссплатформенностью «Windows-Mac-Linux-BSD» для одного бинарника я еще не видел.

Поэтому сие является моим уникальным контентом, хоть и развитием старых идей.

Практическое применение такой штуки очень даже возможно и имеет смысл, поскольку исчезает необходимость генерации нескольких разных сборок под разные ОС. Но естественно что нужно будет больше работы по оптимизации стартовых скриптов.

P.S: Иконку на такой бинарь к сожалению не поставить, увы.

★★★

Проверено: hobbit ()
Последнее исправление: hobbit (всего исправлений: 8)

А где тут собственно бинарник? Это скорее текстовик.
Немного интересен был cosmopolitan libc, но тоже это больше на игрушку какую-то похоже, чем что-то полезное

mittorn ★★★★★
()
Ответ на: комментарий от mittorn

Ну можно точно также запихать в архив бинарники для разных ОС и получить такой же результат.

Не порть момент вообщем - оно запускается (!) на венде, маке и линуксе. Это победа.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от mittorn

И чё, если есть А то Б ненужно? :D Вот придрался то. К слову, космополитан написанный женскийм воплощением Фабриса беларда конечно прикольный, но я никогда не видел его реального применения нигде. Вот прям вообще никогда почему то.

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от mittorn

Во-первых спасибо за ссылки - ценю что я не один такой. Во-вторых, то что я описал как раз самый рабочий вариант, который максимально близок к пользователям. Это абсолютно точно не игрушка. PoC заключается лишь в комбинировании Windows Batch и bash, но не в упаковке шелл-скрипта и zip-пакета.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от hobbit

Спасибо, но я уже был женат, ездил на ламборгини, жил заграницей и имел сверхдоходы.

Звезда на ЛОРе на этом фоне - не актуальна.

alex0x08 ★★★
() автор топика

В принципе Америку я не открыл - такое известно давно и давно используется на практике

да. но с зашкаливающим на лоре ростом школоты, судорожно выбирающей/меняющей дистрибутивы, выковыривающей systemd и pulseaudio и т.д. и т.п…..

В общем, на этом унылом фоне отрадно видеть такие статьи, хоть и не новые :)

aol ★★★★★
()

С телефона полностью читать лень, но APE уже придумали, да.

А вообще - хорошо. Будет еще один способ.

wandrien ★★
()

Все что мы делаем — отражается эхом в вечности, надеюсь что меня запомнят по этой работе, ибо творил я во славу ультрахардкора.

Главное чтобы не затерялись как слезы в дожде;)

Идея интересная, предлагаю развить концепцию. Многие скрипты для установки проприетарщины содержат в себе упакованные бинарники для целевой платформы. С таким скриптом можно запускать целевой бинарник на нужной платформе прямо из скрипта.

einhander ★★★★★
()
Ответ на: комментарий от aol

Так накати стопку за старую школу )

P.S. Две по двадцать это сорок - лучшее что дал 21 век это толпы зумерш с «Daddy Issues», желающих реализовать свои инцестуозные фантазии с моим старым телом.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от einhander

Ну нет, чистый бинарь это риск, поэтому и сделал тестовый проект на managed-платформе.

alex0x08 ★★★
() автор топика

Все что мы делаем — отражается эхом в вечности, надеюсь что меня запомнят по этой работе, ибо творил я во славу ультрахардкора

жесть

Ожидание: перевод или перемзобретение αcτµαlly pδrταblε εxεcµταblε / cosmopolitan

Реальность: java

Ожидание: один бинарник на четыре системы

Реальность: скрипт

t184256 ★★★★★
()
Последнее исправление: t184256 (всего исправлений: 1)
Ответ на: комментарий от LINUX-ORG-RU

женскийм воплощением Фабриса беларда

Им в одном мире не тесно?

t184256 ★★★★★
()
Ответ на: комментарий от t184256

Ой божечки ужос какой - я разрушил чьи-то ожидания. Страсти-то какие.

Проблема с cosmopolitan в том что ты - не его автор, скорее всего даже никогда не использовал эту штуку. Если не вообще только сегодня нагуглил, ради того чтобы обосрать чужую статью.

cosmopolitan - красивое решение но к сожалению концептуально не рабочее, достаточно посмотреть примеры и оценить возможную сложность при попытке реализовать хотя-бы Windows-Linux бинарник с каким-то гуем:

/**
 * @fileoverview GUI Example
 *
 * Cosmopolitan has had a razor sharp focus on making sockets and stdio
 * work well across platforms. When you call a function like read(), it
 * will just work on platforms like Windows too. In order to do that we
 * need to support the WIN32 API, which you can use, but please note it
 * isn't polyfilled on other platforms in the same way as POSIX APIs.
 */

Но опять же, возможно ты гений разработки и сможешь реализовать хотя-бы демо-проект, который я тут показал без «богомерзкой джавы» и скриптов. Дерзай. Ждем всем ЛОРом, как говорится.

alex0x08 ★★★
() автор топика

Так и не понял зачем нужен скрипт.

Jar же под дабл клику мышкой запускается. Или это только в Windows так, а в Linux/Mac нужен обязательно какой-то скрипт запуска и дабл клик не запускает программу?

fsb4000 ★★★★★
()
Последнее исправление: fsb4000 (всего исправлений: 1)
Ответ на: комментарий от fsb4000

Чтобы .jar запускался по клику в виндах, нужна установленная JDK/JRE, причем не просто распакованная а именно установленная - исталлятор прописывает в реестр обработку .jar файлов.

Скрипт же сам скачивает JRE если ее нет на машине и затем запускает.

alex0x08 ★★★
() автор топика

То что я покажу ниже в этой статье — «Proof of Concept» (PoC), доказательство что сделать единый запускаемый бинарник под четыре абсолютно разные и несовместимые платформы технически возможно.

Погоди, погоди. Ты обещаешь единый бинарник на несколько платформ, а в реальности показываешь скрипт, запускающий джава программу на несколько платформ. У меня несколько вопросов:

  1. Что собственно ты называешь «бинарником»? Склейку скрипта с джава-байт-кодом?

  2. Что мне мешает запустить джава программу на разных платформах без твоего скрипта?

  3. Слабо провернуть то же самое с компилируемыми (в исполняемые файлы) языками? Навскидку, нужно всего лишь скомпилировать код под разные платформы, склеить их все со скриптом, скриптом вытащить нужный бинарник и запустить его. Это все ещё не особо интересно, но хотя бы ближе к твоему обещанию ИМХО.

  4. Зачем ты лжёшь?

filosofia
()
Ответ на: комментарий от filosofia

Что собственно ты называешь «бинарником»? Склейку скрипта с джава-байт-кодом?

Исполняемую программу. Почитай SICP ради интереса чтоли.

Что мне мешает запустить джава программу на разных платформах без твоего скрипта?

Смысл был в том чтобы показать как одна неизменяемая программа, сама, без внешней помощи может запускаться везде.

Чтобы «без помощи моего скрипта» запустить джава программу где-бы то ни было, нужно чтобы там стояло JRE/JDK и запускать придется вручную: java -jar мойбинарь.jar

Слабо провернуть то же самое с компилируемыми (в исполняемые файлы) языками?

Технически разницы не будет, смысл тот же самый.
Джава лишь подручный пример, с ней просто кода меньше и сборка проще.

Навскидку, нужно всего лишь скомпилировать код под разные платформы, склеить их все со скриптом, скриптом вытащить нужный бинарник и запустить его

Вот видишь какой ты умный, все знаешь. А теперь иди и делай.

alex0x08 ★★★
() автор топика

Тут нужна картинка про троллейбус из буханки хлеба.

X512 ★★★★★
()
Ответ на: комментарий от Shushundr

Без интернета не работает…

Но на написание сообщения интернета почему-то хватило. Как так?

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

Смысл был в том чтобы показать как одна неизменяемая программа, сама, без внешней помощи может запускаться везде.

Зависимость от интернета ты скромно не считаешь «внешней помощью»? Поколение IoT XD

Чтобы «без помощи моего скрипта» запустить джава программу где-бы то ни было, нужно чтобы там стояло JRE/JDK и запускать придется вручную: java -jar мойбинарь.jar

Ну да, а, чтобы запустить твой скрипт, мне нужен интернет. Вот упакуешь JRE внутрь своего скрипта, тогда приходи.

java -jar мойбинарь.jar

Это вообще условность. Чтобы запустить твой скрипт мне тоже нужен bash script.cmd. То, что Линукс с маком могут выполнить это неявно, другой вопрос.

Тебе нужно было не врать, а называть статью «как сделать скрипт, выполняющийся на четырёх платформах» — это именно то, что ты и написал на самом деле.

filosofia
()

вспомнилось когда я делал роллаут проекты. Правда мы делали msi для таких самодостаточных жаба приложений только для винды. Эх, хорошее было время

monkdt
()
Ответ на: комментарий от filosofia

Зависимость от интернета ты скромно не считаешь «внешней помощью»?

Внешняя помощь это про дополнительные действия пользователя. А интернет сейчас есть везде.

Вот упакуешь JRE внутрь своего скрипта, тогда приходи.

Нет никакой проблемы это сделать. Все необходимые стадии есть в тестовом проекте. Смысла нет, тк JRE в архиве 70Мб под одну ОС. Это PoC а не готовое решение, его смысл показать саму возможность, не более. Даже код скачивания увеличил пример в два раза.

Это вообще условность.

Это 99% процентов отказов от использования твоего софта, если что. Маму свою попроси или бабушку запустить что-то вручную через командную строку.

Чтобы запустить твой скрипт мне тоже нужен bash script.cmd.

Нет не нужен. Даже бит executable ставится при сборке. Даже если ты запустишь через ksh - скрипт сам себя перезапустит под башем.

Вообщем ты статью-то прочитай прежде чем гневные комменты писать.

alex0x08 ★★★
() автор топика

Обычные программы либо компилируются под какую-то конкретную ОС и архитектуру процессора, либо же требуют специальное окружение для запуска и работы. Которое еще нужно скачать и установить.

Так у тебя это все и есть. Тут что прикольного - так это скрипт. Лучше бы назвать тему не «Один бинарник на четыре системы», а «один скрипт на четыре системы».

rumgot ★★★★★
()
Ответ на: комментарий от rumgot

«Один бинарник на четыре системы», а «один скрипт на четыре системы».

Тогда прибегут другие вопрошающие ЗА ПРАВДУ, откроют скрипт в блокноте, увидят бинарную часть и начнут писать что ВЫ ВСЕ ВРЕТЕ - тут бинарник!

А потом придут третьи и расскажут что джава это не настоящий бинарник а байткод.

Но SICP ни ты ни они прочитать не потрудились, поэтому дзена не познали.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

Но SICP ни ты ни они прочитать не потрудились, поэтому дзена не познали.

Зато ты это старье прочитал и очень гордишься, как посмотрю. Ну поздравляю.

джава это не настоящий бинарник а байткод.

Ну джаву то не ты изобрел. Или суть темы в том, что ты придумал запускать джаву на 4 системах? А, ну тогда поздоавляю вдвойне.

rumgot ★★★★★
()
Последнее исправление: rumgot (всего исправлений: 2)
Ответ на: комментарий от rumgot

Я больше горжусь что такой PoC вообще смог реализовать, к чему привело в том числе и чтение SICP и «книги дракона» и еще кучи «всякого старья».

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

Открыл я его дял себя не сегодня, но там хотя бы на обертке написано то, что внутри. А тут внутри портал в адъ, но сначала докачается джава.

t184256 ★★★★★
()
Ответ на: комментарий от t184256

Если ты все знаешь и умеешь - легко сможешь повторить на православном петоне, например. Там точно также есть вариант дистрибьюции в виде zip-архива. Если тебе до такой степени джава не нравится.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от mittorn

Тебе важна только корректность названия?

Вообще я немного разочарован, видимо ЛОР уже не тот. Думал мне по логике работы разнос устроют или кто-то найдет не совсем корректную работу в скрипте.

Но увы. Мельчаете вообщем.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

да давно в общем-то. Я почитал быстренько, подробно не стал разбираться, зато сразу вспомнил APE, где реально бинарь исполняется на разных ОС.
APE кстати никто не запрещает использовать и для графического, надо только какой-нибудь fltk или mxtk портировать на него и добавить возможность переключения win32/x11 в рантайме. Нативно wayland завести уже будет посложнее

mittorn ★★★★★
()

незнаю как с bsd\mac но один бинарь на лин вин возможен, если в C не использовать определеные библиотеки то запускатся это будет и в вин и никс.

antech
()
Ответ на: комментарий от antech

Ну тут речь идёт о сложных гуевских приложениях, а не хелловорлд. При своем появлении Java произвела огромное впечатление. Жабу не зря изобрели и в свое время мелкие не раз пытались её своровать. Да и шарп навеян однозначно конструкцией и возможностями java

monkdt
()
Последнее исправление: monkdt (всего исправлений: 3)
Ответ на: комментарий от gavrilovegor519

Возможно, это libc от читательницы этого журнала

mittorn ★★★★★
()
Ответ на: комментарий от antech

тут основная проблема в glibc который работает не на библиотечном уровне, а на уровне сисколов. Так можно было бы сделать загрузчик elf/pe и дёргать его из кода, грузить системные апи для открытия окон и какой-нибудь opengl для отрисовки, при этом такое будет прекрасно работать в windows, в котором весь юзерспейс библиотечный, а libc отвязан от системы и может быть загружен многократно в процесс, но в linux glibc будет то и дело вставлять палки в колёса. Чтобы загрузить реализацию opengl, надо загрузить ld-linux, glibc, это всё будет писать в TLS и конфликтовать с другими libc. Всё конечно можно теоретически обойти, но это уже будет костылями под конкретную libc. Нельзя просто подгрузить libc.so.6 в процесс чтобы при этом всё нормально работало. Как можно было бы решить это? Вынести TLS, аллокаторы и загрузчик elf в какой-нибудь отдельный libsystem (не путать с libsystemd), а libc реализовать поверх него. Тогда можно было бы реализовать этот libsystem в других системах и пускать код собранный под glibc даже без перекомпиляции, просто будет какой-то исполняемый файл, который будет запускать libsystem и уже превращаться в нужный процесс. А чтобы сделать это всё ещё прозрачным, можно превратить это в APE, чтобы имя процесса на windows было правильным.
Останется сделать обёртки для winapi, stdcall opengl (если i386 ещё кому-то нужен вообще), портировать реализацию wayland для haiku от X512 на user.dll/gdi32.dll и будет вам универсальное графическое приложение. При этом гарантировано не конфликтующее с системными драйверами в отличие от хвалённого флетпака, не требующее грёбанных контейнеров для работы. Тулкит конечно придётся с собой тащить, но это уже относительно мелочи. Если людей устраивает пихание всего включая mesa с llvm в контейнер ради запуска браузера, в котором от этого аппаратное ускорение отвалится, то то, что там окажется условный Qt-wayland со всем набором зависимостей вряд ли кого-то смутит. На темы тем более всем пофиг, хотя конечно стоит сделать какую-нибудь прослойку для интеграции системной темы

mittorn ★★★★★
()
Ответ на: комментарий от mittorn

Судя по этому комменту - опыт у тебя есть и серьезный, может стоит взяться сделать описанное? Хотя-бы на уровне прототипа? У меня просто не хватит уровня в нативной разработке для таких дел, при всем желании.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

А у меня времени и мотивации не хватит. Хватило только на исследование такой возможности.
По большей части интереса нет т.к большая часть работы там идёт по совместимости с windows, а сообществу это не сильно надо. Да и вообще только под интеловскую архитктуру. Если не надо будет пересобирать софт, разработчики обленятся и перестанут делать опенсорс. Вряд ли оно затащится в upstream, а значит это будет ещё одна никому ненужная libc, которая если и будет совместима с какой-то версией glibc, то быстро устареет. Так же это упростит жизнь разработчикам проприетарного софта, а значит в GNU это не примут по идеологическим соображениям
Если не удастся TLS вынести в другое место (а он глубоко сидит) то придётся ломать совместимость со старым софтом.
Пример того, как TLS ломается - невозможно загрузить в один процесс одновременно неизменённый android bionic (а так же скомпилированный с ним софт) и glibc. Если в glibc процесс подгрузить android opengl драйвера, то в одни и те же регистры пишется несовместимая информация и libc падает. Из-за этого для работы libhybris приходится пересобирать половину андройда из исходников т.к там доступ к TLS реализован в виде макросов с inline asm, и как-либо запатчить это в бинарях нереально.
Ещё кстати не учёл одну штуку, на linux x86_64 модель данных lp64, а на windows - llp64, это может немного усложнить использование одних и тех же библиотек под windows и linux. Но в wine с этим как-то справляются.
Ну и последнее - куча софта, дёргающего syscall напрямую. Придётся всё это патчить, иначе будет никому не нужный глюкодром

mittorn ★★★★★
()
Ответ на: комментарий от mittorn

А у меня времени и мотивации не хватит.

Такой PoC оставит свой след, будет меньше вопросов из серии ‘а кто ты такой?’. Само собой что это не для массового использования, просто техническое демо.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

из poc у меня где-то валялся загрузчик который запускал приложение линуксовое под windows и подсовывал ему функции из cygwin, правда нормально это не работало из-за несовпадающих структур, но технически оно исполнялось, просто readdir возвращал неверные данные. Нужна настоящая libc, на это мотивации и не хватает. В cosmopolitan libc это всё есть, но уже доведено до ума. Вот и получается логическое продолжение - сделать чтобы можно было грузить системные библиотеки и в windows и в glibc и делать обёртку для графики. А тут уже след будет куда менее заметный

mittorn ★★★★★
()

Та, блин, стоп. Прочитал первые 4 абзаца, думал мне показалось но нет, мне НЕ показалось. Это НЕ бинарник и оно требует сразу несколько сред исполнения в каждой из систем. Причём джава не является родной ни в одной из них.

Просто с такими подходами лучше написать питон-скрипт, который определит систему и распакует из архива нужный для неё бинарник. По крайней мере в 2 из 4 систем питон родной.

kirill_rrr ★★★★★
()
Последнее исправление: kirill_rrr (всего исправлений: 2)
Ответ на: комментарий от kirill_rrr

Ну вот,началось. Снова.

Уважаемый «борец за ПРАВДУ», выше по треду уже обсудили и почему я назвал это именно бинарником и про вариант на петоне и про православие - потрудитесь прочесть.

alex0x08 ★★★
() автор топика

Поэтому для полной радости, я добавил проверку версии и автоматическое скачивание JRE для Windows и Linux платформ.

Дальше даже не читал. Бинарник не будет работать без наличия сети Интернет? Да фтопку. У нас полстраны сидит в сетях предприятий без доступа в Интернет. Нужные пакеты приходится флешками переносить, и для кадой системы свои заморочки: для apt - так, для pip - эдак,
даже для dbeaver плагины через три звизды колено приходится тягать. А тут еще ты.

Xintrea ★★★★★
()
Ответ на: комментарий от Xintrea

Чувак блин, окстись )

Это всего лишь прототип, демо, демострация возможности.

Какие предприятия? Какое куда переносить?

Там запускается демо-приложение из одного класса, которое просто окружение печатает, а ты претензий выкатил как на госприемке до изобретения автокада.

У нас полстраны сидит в сетях предприятий без доступа в Интернет. >Нужные пакеты приходится флешками переносить

Ты из «ящика» чтоли сообщение написал? Ну сочуствую тогда да, у вас там особый секретный путь к счастью.

alex0x08 ★★★
() автор топика

Вот тут находится огромная статья с примерами на разных языках.

Вот тут находится проект для создания кросс-платформенных самораспаковывающихся архивов под разные типы Unix, используется та же идея.

Нужны ссылки к тутам.

mydibyje ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.