IBM®
Перейти к тексту
    в России и странах СНГ [изменить]    Условия использования
 
 
   
    Главная страница    Продукты    Услуги и решения    Поддержка и загрузка    Мой профиль    
Перейти к тексту

developerWorks Россия  >  AIX и UNIX  >

Портируемость приложений в гетерогенных UNIX-средах

Создайте модульную систему сборки

developerWorks
Опции документа

Опции документа, требующие включения JavaScript, не отображаются

Обсудить

Исходные тексты примера


Выскажите мнение об этой странице

Помогите нам улучшить содержание


Уровень сложности: средний

Ю Шен, программист, IBM

07.04.2008

Используйте систему сборки для автоматического портирования Java(TM)-проектов с платформенно-зависимыми расширениями на гетерогенных UNIX(R)-платформах.

Введение

Создание Java™-приложений с применением Java Native Interface (JNI) может стать сложным испытанием. Создание кода на C/C++ сама по себе достаточно сложная работа, кроме того, обеспечение поддержки системы сборки также является трудоемкой задачей. В то время как число существующих платформ увеличивается в разы, система сборки для них без тщательной проработки может оказаться неработающей. Как вариант, для каждой отдельной платформы можно создавать специальную (только для этой платформы) систему сборки, хотя это достаточно неудобно и влечет большие расходы.

Чтобы гарантировать переносимость программ для множества гетерогенных UNIX®-платформ, система сборки должна быть заменяемой. Можно создать мощную систему сборки путем интеграции Apache Ant, набор компиляторов GNU (GNU compiler collection, GCC), Make и Subversion. Система сборки должна быть модульной, чтобы добавление или удаление поддержки новой платформы могло быть легко осуществимым. В ней также должна быть реализована возможность автоматического определения текущей платформы и способность вызывать соответствующие текущей платформе компоненты. Эта статья объясняет, как создать такую систему. Ниже будут рассмотрены следующие вопросы:

  • Интеграция Ant, GCC, Make и Subversion.
  • Разработка заменяемой и переносимой системы сборки и пример ее исходного кода.
  • " Описание флагов GCC, которые могут быть полезными при запуске родных компонентов сборки.
  • Автоопределение используемой среды сборки и разработка зависимостей между этапами процесса сборки.

Интеграция Ant, GCC, Make, и Subversion

Среда сборки в этой статье состоит из многих инструментов с открытым исходным кодом (их можно скачать - см. раздел Ресурсы):

  • Ant;
  • Java Development Kit (JDK);
  • GCC;
  • Make;
  • Subversion;

Рисунок 1 показывает среду сборки. Ant отвечает за:

  • получение кода для текущего рабочего места;
  • вызов JDK для компиляции Java-кода;
  • вызов Make для создания платформенно-зависимого кода.


Рисунок 1. Среда сборки
Среда сборки

Получение исходного кода и управление версиями сборок

Исходный код может быть получен при помощи совместного использования Ant и Subversion, причем можно контролировать версию сборки в течение этого этапа. По ходу процесса разработки версия сборки будет постоянно меняться. Неудобно определять версию сборки каждый раз вручную. Сценарий в листинге 1 извлекает номер версии SVN и использует его в качестве номера сборки.


Листинг 1. Задача для Ant: управление версиями сборок
                
1    <target name="svn-prop">
2      <exec executable="svn">
3        <arg value="--non-interactive"/>
4        <arg value="info"/>
5        <redirector outputproperty="svn.revision">
6          <outputfilterchain>
7            <linecontains>
8              <contains value="Revision:"/>
9            </linecontains>
10            <tokenfilter>
11    	      <replacestring from="Revision:" to=""/>
12            </tokenfilter>
13    	  </outputfilterchain>
14        </redirector>
15      </exec>
16      <!--<echo>${svn.revision}</echo>-->
17    </target>
	

Когда эта задача будет выполнена, номер версии SVN будет сохранен в свойство Ant svn.revision. Это свойство может быть использовано позднее как номер сборки. Этот скрипт работает только с англоязычной версией SVN, поскольку фильтр linecontains проверяет строку на наличие фрагмента Revision:.

Следующим действием надо получить исходный код из репозитория SVN. Ниже листинги 2, 3 и 4 показывают сценарии, предназначенные для извлечения исходного кода.


Листинг 2. Ant: проверка на то, был ли уже скачан исходный код из репозитория
                
1    <target name="svn-check">
2      <available type="dir" property="svn.check" file="${local.url}">
3      <echo>${svn.check}</echo>
4    </target>
	


Листинг 3. Ant: получение исходного кода из репозитория
                
1    <target name="svn-checkout" unless="svn.check" depends="svn-check">
2      <exec executable="svn">
3        <arg value="co" />
4        <arg value="${p.root}/${local.url}" />
5      </exec>
6    </target>
	


Листинг 4. Ant: обновление исходного кода
                
1	<target name="svn-update" depends="svn-checkout">
2	  <exec executable="svn">
3	    <arg value="up" />
4	    <arg value="${local.url}" />
5	  </exec>
6	</target>
	

При помощи описанных выше трех шагов мы получили исходный код. Шаг svn-check используется для того, чтобы проверить, не был ли исходный код уже скачан из репозитория. Если искомая ветвь каталога существует, то свойство svn.check устанавливается в значение true. Следующий шаг svn-checkout выполняется только в случае, если код не был уже скачан из репозитория; в зависимости от того, было ли установлено соответствующее свойство - unless="svn.check". После скачивания исходного кода из репозитория шаг svn-update выполняется каждый раз при вызове сценария. Отметьте, что условие проверки unless проверяет только тот факт, было ли установлено свойство. Значение свойства роли не играет.

Сборка Java-классов

Собирать Java-компоненты при помощи Ant достаточно легко. В этом разделе рассмотрен пример создания простой программы.

Листинг 5 и листинг 6 показывают пример класса на Java и сценарий сборки Ant.


Листинг 5. Описание класса на Java
                
1	package hello;

2	public class Hello {

3	  public static void main(String[] args) {
4	    System.out.println("Greeting from build system - java component!");
5	  }
6	}

	


Листинг 6. Ant создает исполняемый файл для кода на Java
                
1   <?xml version="1.0"?>
2   <project default="deploy" basedir=".">

3     <echo message="pulling in property files" />
4     <import file="properties.xml" />

5     <echo message="compile java greeting ${path.dist.classes}" />

6     <target name="compile">
7       <mkdir dir="${path.dist.classes}"/>
8       <javac destdir="${path.dist.classes}" srcdir="${path.src}"/>
9     </target>
10    <target name="deploy" depends="compile">
11     <jar destfile="${path.dist}/HelloWorld.jar" basedir="${path.dist.classes}">
12      <manifest>
13        <attribute name="Main-Class" value="hello.Hello"/>
14      </manifest>
15     </jar>
16     </target>
17     <target name="clean">
18      <delete dir="build"/>
19     </target>
20   </project>
	

Файл property.xml содержит определения некоторых свойств, как показано в листинге 7. Далее этот файл будет активно использоваться в статье.


Листинг 7. Файл свойств
                
1  <project name="Top-Level property definitions" default="echo" basedir=".">
2    <description>
3    Ant file of common properties to be imported by other ant files
4    </description>
5    <property name="path.dist" value="build" />
6    <property name="path.dist.classes" value="build/classes" />
7    <property name="path.src" value="src" />
8    <target name="echo">
9     <echo>build properties</echo>
10   </target>
11  </project>
	

В этом файле показан способ отделения переменных (свойства) от встроенных переменных.

Сборка компонентов JNI

Java-код можно скомпилировать и развернуть используя Ant и JDK, поэтому компонент JNI может быть скомпилирован и развернут при помощи комбинации Ant, Make, GCC и JDK. Это немного трудно, поскольку используется множество инструментов:

  • три компилятора - javah, javac, и GCC;
  • два инструмента для сборки - Ant и Make.
Листинги 8, 9, 10, 11 и 12 показывают сборку компонента JNI, который включает в себя код на Java, платформенно-зависимый код, сценарий Ant и makefile. Рассматриваемый нами JNI-компонент также выводит в консоль приветствие.


Листинг 8. Вывод приветствия при помощи платформенно-зависимого кода
                
1	package hello;

2	public class Test {

3	  public static native void hello();

4	  static {
5	    System.loadLibrary("libhello");
6	  }

7	  /**
8	   * @param args
9	   */
10	  public static void main(String[] args) {
11	      hello();
12	  }

13	}

	


Листинг 9. Заголовочный файл, скомпилированный в классе Hello.class
                
1	/* DO NOT EDIT THIS FILE - it is machine generated */
2	#include <jni.h>
3	/* Header for class Test */

4	#ifndef _Included_Test
5	#define _Included_Test
6	#ifdef __cplusplus
7	extern "C" {
8	#endif
9	/*
10	 * Class:     Hello
11	 * Method:    hello
12	 * Signature: ()V
13	 */
14	JNIEXPORT void JNICALL Java_Test_hello
15	  (JNIEnv *, jclass);

16	#ifdef __cplusplus
17	}
18	#endif
19	#endif
	


Листинг 10. Платформенно-зависимый код
                
1	#include "hello_Hello.h"
2	#include <stdio.h>
3	JNIEXPORT void JNICALL Java_Test_hello
4	  (JNIEnv * env, jclass jobj) {
5	    printf("Greeting from build system - jni component!\n");
6	}
	


Листинг 11. Сценарий Ant для создания JNI-компонента
                
1	<?xml version="1.0"?>
2	<project default="compile" basedir=".">

3	  <echo message="pulling in property files" />
4	  <import file="properties.xml" />

5	  <echo message="compile jni greeting" />

6	  <target name="compile" depends="compile-native">
7	    <mkdir dir="${path.dist.classes}" />
8	    <javac destdir="${path.dist.classes}" srcdir="${path.src}" />
9	  </target>

10	  <target name="compile-java">
11	    <mkdir dir="${path.dist.classes}" />
12	    <javac destdir="${path.dist.classes}" srcdir="${path.src}" />
13	  </target>

14	  <!-- native tasks start here -->
15	  <target name="compile-header" depends="compile-java">
16	    <javah destdir="${path.dist.classes}" classpath="${path.dist.classes}"
                  class="${class.jni}" />
17	  </target>

18	  <target name="copy-native-includes" depends="compile-header">
19	    <mkdir dir="${path.src.native.include}" />
20	    <copy todir="${path.src.native.include}">
21	      <fileset dir="${path.dist.classes}">
22	        <include name="**/*.h" />
23	      </fileset>
24	    </copy>
25	  </target>

26	  <target name="compile-native" depends="copy-native-includes">
27	    <exec executable="nmake" dir="${path.src.native}" failonerror="true" />
28	    <copy todir="${path.dist.lib}">
29	      <fileset dir="${path.src.native}">
30	        <include name="*.so" />
31	      </fileset>
32	    </copy>
33	  </target>

34	  <target name="clean">
35	    <delete dir="${path.dist}" />
36	    <delete dir="${path.src.native.include}" />
37	    <delete>
38	      <fileset dir="${path.src.native}">
39	        <include name="**/*.so" />
40	      </fileset>
41	    </delete>
42	  </target>

43	</project>
	


Листинг 12. Makefile для Red Hat (linux.x86.mk)
                
1	CC= gcc
2	PROGNAME= libhellolib.so

3	INCLUDES=  -I/home/spark/jdk1.5.0_07/include
4	INCLUDES+= -I/home/spark/jdk1.5.0_07/include/linux

5	CFLAGS=   -o $(PROGNAME) -shared -Wl,-soname,libhello.so
6	CFLAGS+=  $(INCLUDES)
7	CFLAGS+= -static -lc
8	SRCS = hello.c

9	all:
10       	$(CC) $(CFLAGS) $(SRCS)
	

Если воспроизвести действия, показанные выше, можно создать прототип системы сборки. Ниже на рисунке 2 показана последовательность действий, которые выполняет эта система сборки. Итак, получив прототип системы сборки, будем двигаться далее. Остальная часть этой статьи рассматривает преобразование уже имеющейся у нас системы от прототипа до итоговой, реально действующей системы сборки для практического применения.


Рисунок 2. Последовательность действий, применяющаяся в системе сборки
Последовательность действий

Проектирование настраиваемой системы сборки

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

  • Freebsd + x86;
  • Linux® + ia64;
  • Linux + ppc32;
  • Linux + ppc64;
  • Linux + s390;
  • Linux + s390x;
  • Linux + x86;
  • Linux + x86_64;

Делаем платформенно-зависимые сценарии сборки переносимыми и настраиваемыми

GCC на этих платформах работает с различным флагами; команда make может даже иметь различные названия. Таблица 1 приводит сравнение флагов GCC на различных целевых платформах.


Таблица 1. Сравнение флагов на различных платформах
PlatformOPTOSLIBSASFLAGSLDFLAGSXLIBS
freebsd/x86-march=pentium3 -lc_r -lmN/AN/AN/A
Linux/ia64N/AN/AN/AN/AN/A
Linux/ppc32-m32N/A-m32-m32N/A
Linux/ppc64-m64N/A-a64-m64-L/usr/X11R6/lib64 -lX11 -lXft
Linux/s390-fpic -m31N/A-m31-m31N/A
Linux/s390x-fpic -m64N/A-m64-m64N/A
Linux/x86-march=pentium3N/AN/AN/AN/A
Linux/x86_64-fpicN/AN/AN/A-L/usr/X11R6/lib64 -lX11 -lXft

Как видно, флаги GCC (платформенно-зависимая часть родных makefile) отличаются друг от друга. Между тем, шаги сборки родного компонента для каждой платформы в принципе одинаковы. Чтобы не было дублирования, нужен только один makefile на каждом шаге сборки для каждого модуля. Рисунок 3 показывает структуру, которая извлекает переменные (флаги GCC) из постоянных (этапы сборки). Это также делает вновь созданный платформенно-зависимый код легко изменяемым.


Рисунок 3. Этапы сборки и флаги сборки
Этапы сборки и флаги сборки

В этом решении makefile для каждого модуля помещается в каталог <module-name>/native/, а флаги GCC (<platform>.mk) - в каталог make/platform для каждой платформы. В процессе сборки makefile каждого модуля автоматически найдет файл <platform>.mk во время выполнения программы (при помощи приемов, описанных ниже в статье) и включит его в итоговый сценарий сборки для платформы. Кроме того, для компиляции скрипт выбирает платформенно-зависимый код в определенном каталоге, например AIX.s390.

Чтобы сделать предыдущий пример совместимым с этой структурой, необходимо дальше раздробить makefile на отдельные модули. Ниже листинги 13, 14 и 15 показывают как это сделать.

Листинг 13 показывает заданный для определенного модуля файл makefile в применении к предыдущему примеру.


Листинг 13. Характерные для модуля этапы сборки компонента Hello
                
1   include ../../make/defines.mk
2   include ../../make/platform/$(HY_PLATFORM).mk
3   CFLAGS+= $(SRCS)
4   CFLAGS+= $(INCLUDES) $(OPT)
5   CFLAGS+= -static -lc

6   PROGNAME= libhellolib.so
7   include ../../make/rules.mk
	

Листинг14 показывает наиболее часто употребляемые макросы (в файле defines.mk), которые определяют, какой GCC, какой ld и какой платформенно-зависимый код необходимо использовать.


Листинг 14. Макросы в файле defines.mk
                
1   CC= gcc
2   ifneq ($(HY_OS),aix)
3   DLL_LD = $(CC)
4   else
5   DLL_LD = $(LD)
6   endif

7   INCLUDES=  -I/home/robert/jdk1.5.0_07/include
8   INCLUDES+= -I/home/robert/jdk1.5.0_07/include/linux

9   SRCS=$(HY_PLATFORM)/hello.c
	

Листинг 15 показывает платформенно-зависимые флаги GCC (в файле <platform.mk>).


Листинг 15. Платформенно-зависимые флаги GCC в <platform>.mk
                
1   CC= gcc
2   ifneq ($(HY_OS),aix)
3   DLL_LD = $(CC)
4   else
5   DLL_LD = $(LD)
6   endif

7   INCLUDES=  -I/home/robert/jdk1.5.0_07/include
8   INCLUDES+= -I/home/robert/jdk1.5.0_07/include/linux

9   SRCS=$(HY_PLATFORM)/hello.c
	

Листинг 16 показывает основные этапы сборки (в файле rules.mk).


Листинг 16. Основные этапы сборки в файле rules.mk
                
1 all: $(PROGNAME)
2 $(PROGNAME):
3 $(DLL_LD) -o $(PROGNAME) -shared \
4 -Wl,-soname,libhello.so $(CFLAGS)

Как только понадобится поддержка новой платформы, например Linux x86, разработчики могут добавить файл linux.x86.mk в каталог make/platform и поместить платформенно-зависимый (родной) код в каталог <module>/native/linux.x86. По ходу процесса сборки система сборки использует методики, которые будут описаны позже в статье, для поиска корректного компонента "на лету".

Проектирование компоновки исходного кода

Этот раздел описывает методику размещения исходного кода. Обычно сложный проект состоит из многих компонентов. Предположим, что у нас имеется четыре компонента:

  • один написанный на Java компонент, который взаимодействует с пользователями;
  • три JNI-компонента: thread для работы с приложениями реального времени, archive для работы со сжатием и разархивированием и net для работы с сокетами.
В JNI-компонентах Java-код и соответствующий платформенно-зависимый код сильно связаны друг с другом, и поэтому должны располагаться вместе. Сценарий сборки Ant и makefile для этого модуля также должны быть помещены в один и тот же каталог. Рисунок 4 показывает общую компоновку исходного кода.


Рисунок 4. Компоновка кода и сценариев сборки
Компоновка кода и скриптов сборки

При таком размещении каталог make имеет подкаталог platform и два .mk файла: rules.mk и defines.mk. В подкаталоге platform находится по одному файлу <platform>.mk для каждой целевой платформы.

Build.xml также является элементом верхнего уровня иерархии, как и каталог make. При вызове он определяет используемую среду сборки и вызывает при помощи модуля макровызовов команду compile для всех файлов сборки каждого модуля. Затем сomponent.xml вызывает родной (платформенно-зависимый) сценарий сборки, который включает в себя соответствующие платформенно-зависимые флаги GCC, и компилирует связанный с ним платформенно-зависимый программный код согласно инструкциям файла build.xml. Таким образом, можно легко добавить новые модули и поддержку новых платформ. Между тем, другие компоненты не будут затронуты.

Ant не содержит встроенной команды make. Необходимо вызвать команду make при помощи команды <exec>. Поскольку команды make одинаковы на различных архитектурах, при подобном методе вызова они будут дублироваться. Ant предоставляет механизм под названием macro (макрос) для решения этой проблемы. Листинг 17 показывает макрос, названный make, определенный в файле property.xml.


Листинг 17. Макрос make
                
1  <macrodef name="make">
2    <attribute name="dir" />
3    <sequential>
4     <exec failonerror="true" executable="${make.command}" dir="@{dir}">
5       <env key="HY_ARCH" value="${hy.arch}" />
6       <env key="HY_OS" value="${hy.os}" />
7     </exec>
8    </sequential>
9  </macrodef>
	

Листинг 18 показывает, как осуществить вызов макроса make.


Листинг 18. Вызов макроса make
                
	<make dir="${path.src.native}">
	

Наш проект продолжает развиваться, и мы будем добавлять новые компоненты и внедрять поддержку новых платформ. Нам - разработчикам - придется модифицировать систему сборки для адаптации к этим изменениям. Добавление сценариев Ant для новых компонентов и платформ в один центральный сценарий Ant подразумевает, что мы уже изменили доселе стабильный сценарий сборки и тем самым увеличили вероятность возникновения в нем ошибок. В этом случае каждый компонент имеет свой собственный файл build.xml. Центральный сценарий сборки, в свою очередь, собирает задачи каждого подмодуля. Соответственно, каждый компонент становится переносимым. Листинг 19 показывает главный файл build.xml.


Листинг 19. Java-задача в главном файле build.xml
                
1	<target name="compile-java">
2	  <mkdir dir="${path.dist.classes}" />
3	  <call-modules target="compile-java" />
4	</target>
5	<target name="compile-native">
6	  <call-modules target="compile-native" />
7	</target>
8	<target name="clean">
9	  <delete dir="${path.dist}" />
10	  <call-modules target="clean" />
11	</target>
	

Листинг 20 показывает файл build.xml для какого-либо одного модуля.


Листинг 20. Файл build.xml для модуля thread
                
1  <?xml version="1.0"?>
2  <project basedir="." default="compile-java">

3    <echo message="compile thread greeting" />
4    <import file="../../properties.xml" />

5    <property name="p.root" value="${basedir}/../../" />
6    <target name="compile" depends="compile-java, compile-native" />

7    <target name="compile-java">
8	 <javac destdir="${p.root}/${path.dist.classes}"
            srcdir="${p.root}/${path.src}/thread/java" />
9    </target>

10   <!-- native tasks start here -->
11   <target name="compile-header" depends="compile-java">
12   <javah destdir="${p.root}/${path.dist.classes}" classpath=\
                "${p.root}/${path.dist.classes}"
                class="${class.jni}" />
13   </target>

14   <target name="copy-native-includes" depends="compile-header">
15     <mkdir dir="${p.root}/${path.src}/thread/native/include" />
16     <copy todir="${p.root}/${path.src}/thread/native/include">
17       <fileset dir="${p.root}/${path.dist.classes}">
18	   <include name="**/*.h" />
19       </fileset>
20     </copy>
21   </target>

22   <target name="compile-native" depends="copy-native-includes">
23     <echo>${make.command} ${path.src.native}</echo>
24     <make dir="${p.root}/${path.src}/thread/native" />
25     <copy todir="${p.root}/${path.dist.lib}">
26       <fileset dir="${p.root}/${path.src}/thread/native">
27	   <include name="*.so" />
28	 </fileset>
29     </copy>
30    </target>

31    <target name="clean">
32     <delete dir="${p.root}/${path.src}/thread/native/include" />
33     <delete>
34	 <fileset dir="${p.root}/${path.src}/thread/native">
35	   <include name="**/*.so" />
36	 </fileset>
37     </delete>
38    </target>

39  </project>
	

Листинг 21 определяет макрос под названием call-modules (определен в property.xml) для вызова файла build.xml.


Листинг 21. Макрос call-module
                
1   <property name="build.module" value="*" />
2   <property name="exclude.module" value="nothing" />
+
3   <macrodef name="call-modules">
4     <attribute name="target" />
5     <sequential>
6       <subant target="@{target}">
7         <dirset dir="modules" includes="${build.module}" excludes=\
             "${exclude.module}" />
8       </subant>
9     </sequential>
10  </macrodef>
	

Определение среды сборки

Приложение состоит из Java-классов м платформенно-зависимых библиотек. По ходу сборки системе надо определить среду сборки (можно идентифицировать ее вручную или доверить эту задачу встроенным механизмам), в которой выполняется сборка приложения, для того чтобы платформенно-зависимый код был правильно скомпилирован. Как только система сборки определит тип среды сборки, она должна присоединить к сборке соответствующие файлы, чтобы сгенерировать библиотеки. Рисунок 5 показывает процесс для подключения нужного файла свойств (property file) и создания родной библиотеки и JAR-упаковщика. Объяснение отдельных этапов приведено ниже, согласно значениям на рисунке.


Рисунок 5. Подключение корректного файла свойств
Подключение корректного файла свойств
  1. Файл build.xml включает в себя property.xml. В property.xml указаны условия для проверки и свойства, которые Ant использует для идентификации текущей платформы. Листинг 22 показывает сценарий, использующий эту технику. Эти свойства определены в файле property.xml.



    Листинг 22. Использование условий и встроенных свойств для определения текущей платформы

                                
    1	<!-- built-in test conditions -->
    2	<condition property="hy.os" value="linux">
    3	  <os name="linux" />
    4	</condition>
    5	<condition property="hy.os" value="freebsd">
    6	  <os name="freebsd" />
    7	</condition>
    8	<condition property="hy.os" value="aix">
    9	  <os name="aix" />
    10	</condition>
    11	<!-- built-in property os.name -->
    12	<property name="hy.os" value="${os.name}" />
    	

  2. Свойство hy.os передается в макрос make, как показано в листинге 17. В свою очередь, макрос make передается в makefile как среда с именем HY_OS. Та же самая техника применяется к переменной среды HY_ARCH.

  3. Makefile в соответствующем модуле присоединяет к себе флаги согласно значению HY_ARCH. Листинг 23 демонстрирует это.



    Листинг 23. makefile присоединяет к себе флаги, специфичные для данной платформы ( $(HY_PLATFORM).mk )

                                
    ...
    1  include $(HY_HDK)/build/make/platform/$(HY_PLATFORM).mk
    
    2  ifneq ($(HY_OS),freebsd)
    3  OSLIBS += -ldl
    4  Endif
    ...
    	

  4. Дальше нужно только собрать и упаковать приложение.

Разработка последовательности действий

Последним, что мы рассмотрим, будет разработка последовательности действий. Эта последовательность может быть циклической. Как показано на рисунке 2 (прототип системы сборки), в системе существуют три главные задачи. Первая задача связана со скачиванием кода из SVN, следующая задача - с осуществлением сборки для Java и последняя - с осуществлением сборки для текущей платформы. По ходу выполнения процесса задачи могут уточняться. Рисунок 6 показывает более детализированную систему.


Рисунок 6. Уточненная последовательность действий
Уточненная последовательность действий

Рисунок 7 иллюстрирует дальнейшее уточнение задачи платформенно-зависимой сборки.


Рисунок 7. Дальнейшее уточнение задачи платформенно-зависимой сборки
Дальнейшее уточнение задачи платформенно-зависимой сборки

При необходимости можно загрузить autobuild.zip, который включает в себя один модуль JNI, сценарии сборки для Java и сценарии для платформенно-зависимой сборки. Все задачи, расмотренные в этой статье, включены в этот файл.

Итоги

Эта статья затронула проблему автоматической портируемости Java-проектов с платформенно-зависимыми расширениями на гетерогенных UNIX-платформах. В статье было показано, как разбить проект на общие части и отдельно используемые модули сценария сборки и как сделать разработку модулей более настраиваемой. Также в статье был затронут вопрос разбиения сценария make на общие, одинаковые для всех платформ фрагменты и характерные только для этой платформы, объяснено, как сделать переносимым программный код, зависимый от типа платформы. И наконец, было рассмотрено, как использовать встроенные условия проверки и свойства Ant для определения "на лету" текущей платформы.




В начало


Загрузка

ОписаниеИмяРазмерМетод загрузки
аutomatic build systemau-autobuild.zip7KBHTTP
Информация о методах загрузки


Ресурсы

Научиться

Получить продукты и технологии

Обсудить


Об авторе

фотография автора

Шен Ю (Shen Yu) работает программистом в IBM Application and Integration Middleware Software group в Шанхае (Китай). Он принимал участие в нескольких проектах по интеграции решений на предприятиях, а сейчас он участвует в проекте Apache Harmony. В свое свободное время он занимается живописью.




Выскажите мнение об этой странице


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



ДаНетНе знаю
 


 


12345
 


Поделиться этой статьей:

забобрить забобрить memori сохранить в memori




В начало


IBM, AIX, AIX5L являются зарегистрированной торговыми марками IBM Corporation в Соединенных Штатах Америки и других странах. Java и все связанные с Java торговые марки принадлежат Sun Microsystems, Inc. в Соединенных Штатах Америки и других странах. Linux является торговой маркой Линуса Торвальдса (Linus Torvalds) в Соединенных Штатах Америки и других странах. UNIX является зарегистрированной торговой маркой The Open Group в Соединенных Штатах Америки и других странах. Другая компания, продукт или название услуги могут быть торговыми марками или знаками обслуживания, принадлежащими иным физическим или юридическим лицам.

IBM обладает всеми авторскими правами касательно информации, расположенной на developerWorks. Использование информации приведенной на этом ресурсе без явного письменного разрешения от IBM или первоначального автора запрещены. Если Вы желаете использовать информацию с developerWorks, пожалуйста воспользуйтесь регистрационной формой для того, чтобы связаться с нами запрос на использование материалов developerWorks Россия.

    IBM в России Конфиденциальность Контакты