Сборка одной банки на платформу для многоплатформенного приложения SWT

К этой теме уже есть пара вопросов, но ни один из них не работает должным образом.

Вот их список:

Мое требование состоит в том, чтобы создать ant-скрипт, который создает один jar-файл для каждой платформы, т.е. один для Windows x86, один для Windows x64, Linux x86/x64 и так далее.

У кого-нибудь есть дальнейшее понимание?

Используя вышеупомянутые методы, я не смог найти работоспособное решение. Он либо заканчивался тем, что файл jar SWT не загружался автоматически, либо не включался в путь к классам.

Если кто-то может придумать рабочий пример (в идеале включая полный исходный код), это было бы здорово!

1 ответ

Решение

Итак, я наконец-то нашел решение, которое успешно протестировал на трех платформах.

Два магических компонента - это jar-in-jar-loader и правильный скрипт сборки.

Сценарий сборки с комментариями можно найти здесь:

<project name="RandomApp" basedir="." default="clean-build">

    <property name="src.dir" value="src" />

    <!-- Define the necessary paths -->
    <property name="build.dir" value="bin_temp" />
    <property name="lib.dir" value="lib" />
    <property name="lib.deploy.dir" value="lib_swt" />
    <property name="classes.dir" value="${build.dir}/classes" />
    <property name="jar.dir" value="${build.dir}/jar" />
    <property name="img.dir" value="img" />
    <property name="res.dir" value="res" />

    <!-- Define the main class -->
    <property name="main-class" value="org.baz.desktop.randomapp.gui.RandomApp" />

    <path id="base-classpath">
        <fileset dir="${lib.dir}" includes="**/*.jar" />
    </path>

    <!-- Define the class path -->
    <path id="classpath">
        <fileset dir="${lib.dir}" includes="**/*.jar" />
        <fileset dir="${lib.deploy.dir}" includes="**/swt_win32_x64.jar" />
    </path>

    <!-- Clean previously built files -->
    <target name="clean">
        <delete dir="${build.dir}" />
    </target>

    <!-- Compile the project -->
    <target name="compile">
        <mkdir dir="${classes.dir}" />
        <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath" includeantruntime="false" />
    </target>

    <macrodef name="createclasspath">
        <attribute name="name" />
        <attribute name="swtlib" />
        <sequential>
            <pathconvert property="@{name}.classpath" pathsep=" ">
                <path refid="base-classpath" />
                <fileset dir="${lib.deploy.dir}" includes="**/swt_@{swtlib}.jar" />
                <mapper>
                    <chainedmapper>
                        <flattenmapper />
                        <globmapper from="*.jar" to="*.jar" />
                    </chainedmapper>
                </mapper>
            </pathconvert>
        </sequential>
    </macrodef>

    <!-- Define classpath and create the jar folder -->
    <target name="pre_jar" depends="compile">
        <!-- Linux 32bit -->
        <createclasspath name="win86" swtlib="win32_x86" />
        <!-- Linux 64bit -->
        <createclasspath name="win64" swtlib="win32_x64" />
        <!-- Windows 32bit -->
        <createclasspath name="linux86" swtlib="linux_gtk_x86" />
        <!-- Windows 64bit -->
        <createclasspath name="linux64" swtlib="linux_gtk_x64" />
        <!-- MacOS 32bit -->
        <createclasspath name="macos86" swtlib="macos_x86" />
        <!-- MacOS 64bit -->
        <createclasspath name="macos64" swtlib="macos_x64" />

        <mkdir dir="${jar.dir}" />
    </target>

    <macrodef name="createjar">
        <attribute name="swtlib" />
        <attribute name="swtclasspath" />
        <sequential>
            <jar destfile="${jar.dir}/${ant.project.name}_@{swtlib}.jar" basedir="${classes.dir}">
                <manifest>
                    <attribute name="Main-Class" value="org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader" />
                    <attribute name="Rsrc-Main-Class" value="${main-class}" />
                    <attribute name="Class-Path" value="." />
                    <attribute name="Rsrc-Class-Path" value="./ @{swtclasspath}" />
                </manifest>

                <zipgroupfileset dir="${lib.dir}" includes="**/jar-in-jar-loader.jar" />
                <zipfileset dir="${lib.deploy.dir}" includes="**/swt_@{swtlib}.jar" />
                <zipfileset dir="${lib.dir}" includes="**/*.jar" excludes="**/jar-in-jar-loader.jar" />
            </jar>
        </sequential>
    </macrodef>

    <!-- Create the jar files -->
    <target name="jar" depends="pre_jar">
        <!-- Linux 32bit -->
        <createjar swtlib="linux_gtk_x86" swtclasspath="${linux86.classpath}" />
        <!-- Linux 64bit -->
        <createjar swtlib="linux_gtk_x64" swtclasspath="${linux64.classpath}" />
        <!-- Windows 32bit -->
        <createjar swtlib="win32_x86" swtclasspath="${win86.classpath}" />
        <!-- Windows 64bit -->
        <createjar swtlib="win32_x64" swtclasspath="${win64.classpath}" />
        <!-- MacOS 32bit -->
        <createjar swtlib="macos_x86" swtclasspath="${macos86.classpath}" />
        <!-- MacOS 64bit -->
        <createjar swtlib="macos_x64" swtclasspath="${macos64.classpath}" />
    </target>

    <target name="clean-build" depends="clean,jar" />

</project>

Что он в основном делает, так это определяет базовый путь к классам без какой-либо библиотеки SWT. Затем он создает пути к классам для конкретной платформы, используя базовый и добавляя соответствующую библиотеку SWT платформы.

jar Затем задача создает отдельный jar-файл для каждой платформы, используя эти пути к классам и jar-in-jar-loader.

И это все, полностью автоматизированный способ создания jar-файлов для каждой (поддерживаемой) платформы.


Я создал пример проекта, который люди могут загрузить и опробовать. Это легкая отправная точка для мультиплатформенного приложения.

https://www.dropbox.com/s/ianrbl4bn0fmsdi/SWTApplication.7z


Обновление:

Мне удалось значительно сократить муравейник, правильно используя macrodef:)

Другие вопросы по тегам