Глава 5
Mxx_ru для C/C++ проектов

5.1 Введение

Mxx_ru предоставляет набор готовых средств для поддержки компиляции C/C++ проектов. Эти средства описаны в файле mxx_ru/cpp, который необходимо загружать директивой require:


1  require ’mxx_ru/cpp’
2  ...

Для поддержки C/C++ в Mxx_ru выделены важные понятия: toolset и obj_placement.

Mxx_ru предоставляет готовые классы для таких типов целей, как exe-файл, dll-файл (с поддержкой библиотек импорта), lib-файл, композитный проект.

5.1.1 Понятие toolset

Toolset — это набор инструментов, применяемых для компиляции проекта. Проще говоря, toolset определяет тип, версию и другие особенности конкретного компилятора на конкретной платформе.

Mxx_ru уже адаптирован к ряду компиляторов. В частности поддерживаются компиляторы Borland C++ (версий 5.* на платформе mswin); Visual C++ (версий 7.* и 6.* на платформе mswin); GNU C++ на платформах unix, mswin (через порты mingw и cygwin); с89 для HP NonStop (native-версия и кросс-компилятор из eToolkit для mswin).

Для корректной работы Mxx_ru тип toolset должен быть указан Mxx_ru во время настройки (см.  5.2 на стр.  59).

Toolset представляется объектом класса, производного от Mxx_ru::Cpp::Toolset. Объект-toolset создается Mxx_ru и используется для всего проекта (т.е. для проекта, имя файла которого указано интерпретатору Ruby и для всех его подпроектов). Объект-toolset нельзя заменить. Получить доступ к объекту-toolset можно через метод toolset().

Имена toolset

Каждый toolset имеет собственное имя, доступное через метод name класса Mxx_ru::Cpp::Toolset. Это имя может использоваться для настройки проекта на конкретный компилятор. Например:


1  Mxx_ru::Cpp::Exe_target.new( "prj.rb" ) {
2   ...
3   if "vc" == toolset.name
4   # Адаптация к Visual C++.
5   cpp_source( "mswin/vc/exception_handler.cpp" )
6   elif "gcc" == toolset.name
7   # Адаптация к GNU C++.
8   cpp_source( "gcc/exception_handler.cpp" )
9   end
10   ...
11  }

Определенные на данный момент имена компиляторов перечислены в таблице  5.1.




bcc Компилятор Borland C++ (платформа mswin).


c89_nskКомпилятор c89 для HP NonStop (платформы HP NonStop и mswin).


gcc Компилятор GNU C/C++ (платформы unix, mswin).


vc Компилятор Visual C++ (платформа mswin).



Таблица 5.1: Имена реализованых toolset.

Теги toolset

Т.к. toolset адаптирован к конкретному компилятору на конкретной платформе, то в проекте можно использовать toolset для настройки проекта на данную платформу. Для этих целей в toolset есть понятие тегов. Тег — это уникальны текстовый ключ, которому сопоставлено текстовое значение. Теги устанавливаются самими toolset, а так же их можно указать при настройке Mxx_ru.

Для получения значения тега предназначен метод tag(a_name, a_default=nil). Если в toolset установлен тег с таким именем, то возвращается его значение. В противном случае возвращается значение аргумента a_default. Если тег не установлен и a_default==nil, то порождается исключение Mxx_ru::Cpp::Toolset::Unknown_tag_ex.

Ряд тегов считаются обязательными, они должны быть определены для всех toolset на всех платформах (см. таблицу  5.2).




host_os Операционная система, на которой производится компиляция.


target_osОперационная система, для которой производится компиляция.



Таблица 5.2: Обязательные теги для всех toolset.

Значения тегов host_os и target_os могут различаться в случае использования кросс-компилятора, например, c89 для HP NonStop.

Операционные системы идентифицируются перечисленными в таблице  5.3 именами.




mswin 32-битовый вариант Microsoft Windows.


tandem_ossПодсистема OSS (Open System Services) для HP NonStop.


unix Различные варианты Unix.



Таблица 5.3: Имена операционных систем.

На платформе unix должен быть определен обязательный тег unix_port, который определяет конкретный тип unix. Рекомендуется использовать перечисленные в таблице  5.4 значения1.




bsd FreeBSD/NetBSD/OpenBSD.


cygwinCygwin на Microsoft Windows.


linux GNU/Linux.


solarisSun Solaris.



Таблица 5.4: Имена вариантов Unix.

При настройке Mxx_ru могут быть указаны и другие теги, которые необходимы проекту.

Пример работы с тегами:


1  Mxx_ru::Cpp::Dll_target.new( "my.rb" ) {
2   # Под Unix помещаем результат компиляции в подкаталог lib.
3   if "unix" == toolset.tag( "target_os" )
4   target_root( "lib" )
5   end
6   target( "my" )
7  
8   # Если используется архитектура процессора, отличная от Intel x86,
9   # то ее имя должно быть указано в собственном теге "arch".
10   if "x86" == toolset.tag( "arch", "x86" )
11   ...
12   else
13   ...
14   end
15   ...
16  }

5.1.2 Понятие obj_placement

Mxx_ru позволяет управлять размещением результатов компиляции и линковки C/C++ проекта. Для этих целей используется понятие obj_placement — объекта производного от Mxx_ru::Cpp::Obj_placement класса. Этот объект указывает Mxx_ru куда помещать объектные файлы, куда библиотеки, куда скомпилированные ресурсные файлы и т.д.

Проект может сам указать необходимый ему тип obj_placement. Для этого предназначен метод obj_placement. Например:


1  Mxx_ru::Cpp::Dll_target.new( "my.rb" ) {
2   ...
3   obj_placement(
4   Mxx_ru::Cpp::Runtime_subdir_obj_placement.new(
5   "output" ) )
6   ...
7  }

Проект может назначить глобальный obj_placement при помощи функции global_obj_placement. В этом случае действие нового obj_placement будет распространяться на все подпроекты.

Попытка установить одновременно и локальный и глобальный obj_placement является ошибкой и приведет к исключению. Рекомендуется устанавливать только глобальный obj_placement в самом верхнем, обычно композитном, проекте.

В состав Mxx_ru входят два штатных класса для obj_placement:

Например, если есть дерево каталогов:


  |-- engine
  |-- interface
  |   |-- high
  |   ‘-- low
  ‘-- monitor

и используется Source_subdir_obj_placement, то после компиляции дерево каталогов примет вид:


  |-- engine
  |   ‘-- o
  |-- interface
  |   |-- high
  |   |   ‘-- o
  |   |-- low
  |   |   ‘-- o
  |   ‘-- o
  ‘-- monitor
      ‘-- o

Если же используется Runtime_subdir_obj_placement с подкаталогом output в качестве корневого и с режимом компиляции debug, то получится следующе дерево каталогов:


  |-- engine
  |-- interface
  |   |-- high
  |   ‘-- low
  |-- monitor
  ‘-- output
      ‘-- debug
          |-- engine
          |-- interface
          |   |-- high
          |   ‘-- low
          ‘-- monitor

При этом все результаты компиляции, включая exe, dll, lib и т.д., будут помещены в output/debug.

Если obj_placement не задан явно, то используется Source_subdir_obj_placement.

5.1.3 Цели для C/C++ проектов

Для C/C++ проектов в Mxx_ru существуют следующие классы целей:

Для C/C++ проекта в проектном файле необходимо создать и передать в функцию Mxx_ru::setup_target объект одного из этих классов.

Все классы имеют конструкторы, которые могут получать блок кода (специфическая особенность языка Ruby). Поэтому для описания проекта не обязательно создавать свой класс, производный от одного из указанных выше классов. Достаточно создать объект одного из существующих классов и передать в его конструктор блок, в котором производится настройка проекта:


1  Mxx_ru::Cpp::Exe_target.new( ... ) { ... }

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


1  # Правильно.
2  Mxx_ru::Cpp::Exe_target.new( "my.rb" ) { target( "my" ) c_source( "my.c" ) }
3  
4  # Правильно.
5  Mxx_ru::Cpp::Exe_target.new( "my.rb" ) { target( "my" )
6   c_source( "my.c" ) }
7  
8  # Правильно.
9  Mxx_ru::Cpp::Exe_target.new( "my.rb" ) {
10   target( "my" )
11   c_source( "my.c" )
12  }
13  
14  # Не правильно!
15  Mxx_ru::Cpp::Exe_target.new( "my.rb" )
16   {
17   target( "my" )
18   c_source( "my.c" )
19   }
20  
21  # Правильно. Обратный слэш в конце строки означает,
22  # что на следующей строке находится продолжение данной строки.
23  Mxx_ru::Cpp::Exe_target.new( "my.rb" ) \
24   {
25   target( "my" )
26   c_source( "my.c" )
27   }

5.1.4 Порядок выполнения build/clean

При построении C/C++ целей выполняются следующие действия:

  1. Выполняется построение всех подпроектов.
  2. Выполняется вызов метода build у всех генераторов исходного кода.
  3. Запускается анализатор C/C++ зависимостей.
  4. Выполняется компиляция всех C файлов.
  5. Выполняется компиляция всех С++ файлов.
  6. Если на платформе mswin определены ресурсы, то выполняется компиляция ресурсов.
  7. Если типом цели является lib, то строится статическая библиотека. В случае exe и dll осуществляется линковка exe- или dll-файла соответственно. Если для dll определено расположение библиотеки импорта, то строится библиотека импорта.

При очистке C/C++ целей выполняются следующие действия:

  1. Выполняется очистка всех подпроектов.
  2. Выполняется вызов метода clean у всех генераторов исходного кода.
  3. Удаляются объектные файлы для всех C файлов.
  4. Удаляются объектные файлы для всех C++ файлов.
  5. Если на платформе mswin определены ресурсы, то удаляются скомпилированные ресурсные файлы.
  6. Если типом цели является lib, то удаляется статическая библиотека. В случае exe и dll удаляются exe- и dll-файлы. Если для dll определено расположение библиотеки импорта, то библиотека импорта так же удаляется.

Примечание. Класс Composite_target выполняет построение и очистку только подпроектов.

5.1.5 Режимы runtime

Mxx_ru позволяет строить C/C++ проекты в трех режимах runtime:

Указать режим runtime можно двумя способами:

  1. В проектном файле при помощи функции runtime_mode. Например:


    1  Mxx_ru::Cpp::Exe_target( "prj.rb" ) {
    2   runtime_mode( Mxx_ru::Cpp::RUNTIME_RELEASE )
    3   ...
    4  }
  2. В командной строке посредством аргументов --mxx-cpp-release или --mxx-cpp-debug. Например:


      ruby build.rb --mxx-cpp-release

5.1.6 Локальные, глобальные и распространяемые параметры проекта

Описание C/C++ проекта в Mxx_ru состоит в перечислении таких параметров, как имя результирующего файла, имена исходных файлов и необходимых библиотек, необходимых define-символов, необходимых опций компилятора, линкера и т.д. Часть этих параметров могут относиться только к самому проекту. Например, имена исходных файлов. Но часть параметров, т.к. define-символы и опции компилятора, разделяются на три типа:

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

Пример установления локального define-символа:


1  Mxx_ru::Cpp::Dll_target.new( "my_dll/prj.rb" ) {
2   target( "my_dll" )
3   implib_path( "lib" )
4  
5   cpp_source( "my_dll/impl.cpp" )
6  
7   defines( "MY_DLL_PRJ" )
8  }

Установленный таким образом символ MY_DLL_PRJ будет доступен только при компиляции my_dll/impl.cpp.

Глобальные
параметры распространяются на все проекты.

Глобальные параметры задаются с помощью функций с именами вида global_<имя>, где <имя> — это имя функции для установки локального параметра того же назначения. Например: global_define, global_include_path, global_compiler_option и т.д.

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


1  Mxx_ru::Cpp::Composite_target.new( Mxx_ru::BUILD_ROOT ) {
2  
3   global_include_path( "." )
4  
5   required_prj( "engine/prj.rb" )
6   required_prj( "interface/prj.rb" )
7  }

В этом случае при компиляции всех файлов из проектов engine/prj.rb и interface/prj.rb в качестве пути поиска заголовочных файлов будет использован текущий каталог.

Пример установки глобальной опции компилятора.


1  Mxx_ru::Cpp::Dll_target.new( "packer/prj.rb" ) {
2   ...
3   # Должен использоваться режим выравнивания в 4 байта.
4   if "vc" == toolset.name
5   global_compiler_option( "-Zp4" )
6   end
7   ...
8  }

В этом случае при компиляции всех файлов всех проектов, которые оказались в одном общем проекте с packer/prj.rb компилятору Visual C++ будет передаваться опция -Zp4.

Распространяемые
(upspread) параметры распространяются только на сам проект и на те проекты, которые используют данный проект в качестве подпроекта (вне зависимости от степени вложенности).

Upspread-параметры устанавливаются теми же функциями, что и локальные параметры, но с указанием в качестве второго аргумента константы Mxx_ru::Cpp::Target::OPT_UPSPREAD.

Пример установки upspread define-символа и upspread пути поиска заголовочных файлов:


1  Mxx_ru::Cpp::Lib_target.new( "pcre/prj.rb" ) {
2   target_root( "lib" )
3   target( "pcre.4.5.0" )
4  
5   c_source( "get.c" )
6   c_source( "maketables.c" )
7   c_source( "pcre.c" )
8   c_source( "study.c" )
9  
10   define( "PCRE_STATIC", Mxx_ru::Cpp::Target::OPT_UPSPREAD )
11   define( "SUPPORT_UTF8", Mxx_ru::Cpp::Target::OPT_UPSPREAD )
12  
13   include_path( "pcre", Mxx_ru::Cpp::Target::OPT_UPSPREAD )
14  }

В этом случае при компиляции всех проектов, которые прямо или косвенно используют проект pcre/prj.rb в качестве подпроекта (т.е. указывают его имя, либо имя использующего его проекта в required_prj) в качестве define-символов будут определены PCRE_STATIC и SUPPORT_UTF8, а в качестве пути для поиска заголовочных файлов будет использоваться подкаталог pcre.

5.1.7 Аргумент mxx-cpp-1

Если в командной строке интерпретатору Ruby указан аргумент --mxx-cpp-1, то операции build и clean не распространяются на подпроекты.

Аргумент --mxx-cpp-1 удобно применять, когда выполняются работы над одним подпроектом в составе большого композитного проекта. Запуск построения всего композита может занимать много времени, что расточительно, если вносимые в подпроект изменения не требуют перекомпиляции и перелинковки остальных подпроектов. В этом случае интерпретатору Ruby в командной строке указывается не build.rb, а имя проектного файла и аргумент --mxx-cpp-1:


  ruby some/project/prj.rb --mxx-cpp-1

Аргумент --mxx-cpp-1 может использоваться не только для операции build, но и для операции clean — в этом случае будут удалены только файлы, относящиеся непосредственно к указанного проекту.


  ruby some/project/prj.rb --mxx-cpp-1 --mxx-clean

5.1.8 Аргумент mxx-cpp-no-depends-analyzer

Аргумент --mxx-cpp-no-depends-analyzer2 указывает Mxx_ru не проводить поиск C/C++ зависимостей путем анализа исходных и заголовочных файлов. По умолчанию такой анализ производится, что может значительно замедлять процесс компиляции. Иногда (например, при полной перекомпиляции проекта) поиском зависимостей можно пренебречь. В таких случаях интерпретатору Ruby можно указать агрумент --mxx-cpp-no-depends-analyzer:


  ruby some/project/prj.rb --mxx-cpp-no-depends-analyzer

5.2 Настройка Mxx_ru для работы с C/C++ проектами

Для использования возможностей Mxx_ru для работы с C/C++ проектами необходимо определить переменную среды MXX_RU_CPP_TOOLSET. Значение этой переменной среды должно иметь вид:


  MXX_RU_CPP_TOOLSET=<file> [tag=value [tag=value [...]]

где <file> – это имя .rb-файла из состава Mxx_ru, который отвечает за создания объекта-toolset. Поддерживаемые toolset перечислены в таблице  5.5. Пары значений tag, value будут установлены в качестве тегов выбранного toolset.




mxx_ru/cpp/toolsets/bcc_win32_5Borland C++ 5.* для Microsoft Windows


mxx_ru/cpp/toolsets/c89_etk_nsk c89 для HP NonStop из eToolkit
для Microsoft Windows


mxx_ru/cpp/toolsets/c89_nsk с89 для HP NonStop


mxx_ru/cpp/toolsets/gcc_cygwin GNU C/C++ для Cygwin


mxx_ru/cpp/toolsets/gcc_mingw Minimalist GNU C/C++ для Windows


mxx_ru/cpp/toolsets/gcc_unix GNU C/C++ для Unix


mxx_ru/cpp/toolsets/vc7 Visual C++ 7.* для Microsoft Windows



Таблица 5.5: Список поддерживаемых Mxx_ru toolset.

Примеры:


  export MXX_RU_CPP_TOOLSET=mxx_ru/cpp/toolset/gcc_unix unix=linux arch=x86

  set MXX_RU_CPP_TOOLSET=mxx_ru/cpp/toolset/vc7

5.3 Получение доступа к toolset

Получить объект-toolset из проекта можно обратившись к методу toolset класса Mxx_ru::Cpp::Target. Например:


1  Mxx_ru::Cpp::Exe_target.new( "my/prj.rb" ) {
2   ...
3   if "vc" == toolset.name
4   ...
5   end
6   ...
7  }

Примечание. Т.к. toolset является не статическим методом, его можно вызывать только для созданного объекта-цели. Например, как показано выше, в блоке кода, переданного в конструктор в качестве аргумента.

5.4 Установка режима runtime в проектном файле

Установить режим runtime в проектном файле можно при помощи метода runtime_mode. Значения режима runtime задаются константами: Mxx_ru::Cpp::RUNTIME_DEBUG, Mxx_ru::Cpp::RUNTIME_DEFAULT, Mxx_ru::Cpp::RUNTIME_RELEASE. По-умолчанию используется режим default.

Режим runtime является глобальным параметром. Он распространяется на все проекты сразу. Попытка двух проектов установить разные значения runtime приведет к порождению исключения.

Получить текущее значение режима runtime можно с помощью метода mxx_runtime_mode.

См. так же  5.1.5 на стр.  55.

5.5 Установка типа runtime library

На платформах, которые поддерживают динамически-загружаемые библиотеки, некоторые toolset позволяют выбрать один из двух типов runtime library (rtl): static (код rtl влинковывается в само приложение) и shared (код rtl находится в отдельной dll, к которой линкуется приложение). Если приложение использует собственные dll и передает C++ объекты созданные в одной dll для уничтожения в другую dll, то такое приложение должно использовать shared вариант rtl (в этом случае все dll имеют общий heap).

Установить тип rtl можно при помощи метода rtl_mode. Тип rtl задается с помощью констант: Mxx_ru::Cpp::RTL_DEFAULT (проекту все равно, какой тип rtl будет использоваться), Mxx_ru::Cpp::RTL_STATIC (требуется использовать статический вариант rtl), Mxx_ru::Cpp::RTL_SHARED (требуется использовать разделяемый вариант rtl). По-умолчанию значение rtl_mode установлено в Mxx_ru::Cpp::RTL_DEFAULT (т.н. default режим).

Тип rtl является глобальным параметром. Он распространяется на все проекты сразу. Попытка двух проектов установить разные значения типа rtl приведет к порождению исключения.

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

Пример:


1  Mxx_ru::Cpp::Dll_target.new( "my/prj.rb" ) {
2   target_root( "lib" )
3   target( "my" )
4  
5   rtl_mode( Mxx_ru::Cpp::RTL_SHARED )
6   ...
7  }

Получить текущее значение типа rtl можно с помощью метода mxx_rtl_mode.

5.6 Установка режима многопоточности

На некоторых платформах, например, mswin, требуется явно указывать, нуждается ли приложение в поддержке многопоточности или нет. Для установления режима многопоточности в Mxx_ru используется метод threading_mode. Режим многопоточности определяется с помощью констант Mxx_ru::Cpp::THREADING_DEFAULT (проект не предъявляет никаких требований к режиму многопоточности, является однопоточным, но может работать и в многопоточном приложении), Mxx_ru::Cpp::THREADING_MULTI (проект требует поддержки многопоточности), Mxx_ru::Cpp::THREADING_SINGLE (проект расчитан только на однопоточность, не может использоваться совместно с многопоточными проектами). По-умолчанию режим многопоточности выставлен в Mxx_ru::Cpp::THREADING_DEFAULT.

Если режим многопоточности отличается от Mxx_ru::Cpp::THREADING_MULTI и компилятор нуждается в явном указании режима многопоточности, то используется однопоточный режим.

Режим многопоточности является глобальным параметром. Он распространяется на все проекты сразу. Попытка двух проектов установить разные значения режима многопоточности приведет к порождению исключения.


1  Mxx_ru::Cpp::Dll_target.new( "threads_1/dll.rb" ) {
2   target( "threads_1.4.0" )
3  
4   rtl_mode( Mxx_ru::Cpp::RTL_SHARED )
5   threading_mode( Mxx_ru::Cpp::THREADING_MULTI )
6   ...
7  }

Получить текущее значение режима многопоточности можно с помощью метода mxx_threading_mode.

Примечание. Для некоторых компиляторов, например, Visual C++, имена используемых rtl-библиотек выбираются исходя из типа rtl и режима многопоточности. И не для всех сочетаний возможных типов rtl и режима многопоточности компилятор может иметь библиотеки. Так, Visual C++ не имеет библиотек для однопоточной shared rtl.

5.7 Установка режима RTTI

В некоторых компиляторах режим RTTI (Run-Time Type Identification) по-умолчанию отключен (например, Visual C++) или может быть отключен (например, GNU C++). Если проект нуждается в RTTI, например, для безопасного использования dynamic_cast , то проект должен явно включить режим RTTI. Напротив, если проект не нуждается в RTTI и для проекта критично время исполнения и/или объем результирующего кода, то режим RTTI может быть отключен.

Для включения/выключения режима RTTI предназначен метод rtti_mode, который принимает в качестве значений константы Mxx_ru::Cpp::RTTI_DEFAULT (проекту все равно, используется ли RTTI или нет), Mxx_ru::Cpp::RTTI_ENABLED (проекту необходим режим RTTI) и Mxx_ru::Cpp::RTTI_DISABLED (проекту необходимо отсутствие RTTI).

Режим RTTI является глобальным параметром. Он распространяется на все проекты сразу. Попытка двух проектов установить разные значения режима RTTI приведет к порождению исключения.


1  Mxx_ru::Cpp::Dll_target.new( "threads_1/dll.rb" ) {
2   target( "threads_1.4.0" )
3  
4   rtl_mode( Mxx_ru::Cpp::RTL_SHARED )
5   threading_mode( Mxx_ru::Cpp::THREADING_MULTI )
6   rtti_mode( Mxx_ru::Cpp::RTTI_ENABLED )
7   ...
8  }

Получить текущее значение режима RTTI можно с помощью метода mxx_rtti_mode.

5.8 Указание имени результирующего файла цели

Примечание. Для проектов, которые описываются с помощью Mxx_ru::Cpp::Composite_target нет результирующего файла, поэтому обращения к методам target_root, target, implib_path игнорируются.

5.8.1 Метод target_root

Метод target_root позволяет задать имя каталога, в который должен быть помещен результирущий файл (exe, dll или lib). Размещение результата контролируется с помощью obj_placement (см.  5.1.2 на стр.  51). Если не задан target_root, то результат будет помещен в каталог, который выберет obj_placement. Если же установлен target_root, то результат будет помещен в подкаталог с именем, указанным в target_root, в каталоге, который выберет obj_placement.

Например, пусть obj_placement располагает exe-файлы в текущий каталог. Тогда, если установить в target_root значение out32, то obj_placement поместит результирующий файл в подкаталог out32 текущего каталога.

Важно. Желательно, чтобы метод target_root был вызван перед методом target. Тогда, при обращении к target имя результирующего файла будет автоматически создано с использованием значения target_root. Если же метод target_root вызывается после target, то модифицируется уже назначенное имя результирующего файла. В общем случае, если target_root и target вызываются по одному разу, то результат получается один и тот же. Но, если target_root вызвать два раза (до и после обращения к target, то результат может отличаться от ожидаемого.

5.8.2 Метод target

Метод target позволяет задать базовое имя для результирующего файла. Реальное имя результата будет создано с учетом особенностей целевой платформы. Например, для dll с базовым именем threads_1.4.0 на платформе mswin будет создано реально имя threads_1.4.0.dll, а на платформе unix — libthreads_1.4.0.so.

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

5.8.3 Метод implib_path

Метод implib_path, во-первых, предписывает Mxx_ru построить библиотеку импорта для dll (на тех платформах, на которых такое понятие актуально) и, во-вторых, определяет расположение библиотеки импорта.

В настоящий момент implib_path используется только для dll. Если implib_path не вызывается, то библиотека импорта не строится.

5.8.4 Примеры

Простое указание имени для exe-файла.


1  Mxx_ru::Cpp::Exe_target.new( "hello_world.rb" ) {
2   target( "hello_world" )
3   ...
4  }

Размещение exe-файла в подкаталоге utest.


1  Mxx_ru::Cpp::Exe_target.new( "packer/utest/prj.rb" ) {
2   target_root( "utest" )
3   target( "test_packer" )
4   ...

На платформе mswin результирующая dll помещается в текущий каталог, а библиотека импорта в каталог lib. На платформе unix результирующая библиотека помещается в каталог lib.


1  Mxx_ru::Cpp::Dll_target.new( "oess_1/defs/prj.rb" ) {
2   if "mswin" == toolset.tag( "target_os" )
3   implib_path( "lib" )
4   elsif "unix" == toolset.tag( "target_os" )
5   target_root( "lib" )
6   end
7  
8   target( "oess_defs.1.3.0" )
9   ...
10  }

5.9 Установка типа приложения (консоль/GUI)

Метод screen_mode предназначен для указания типа приложения: консольное или оконное. По-умолчанию, Mxx_ru расчитывает на создание консольного приложения — компилятору и линкеру выставляются специальные опции. Вызвав метод screen_mode можно перевести проект в режим создания оконного (GUI) приложения.

В метод screen_mode необходимо передавать константу Mxx_ru::Cpp::SCREEN_WINDOW для оконного приложения или константу Mxx_ru::Cpp::SCREEN_CONSOLE для консольного приложения.


1  Mxx_ru::Cpp::Exe_target.new( "interface/prj.rb" ) {
2   ...
3   screen_mode( Mxx_ru::Cpp::SCREEN_WINDOW )
4   ...
5  }

Параметр screen_mode является локальным для проекта, он не распространяется ни на подчиненные проекты, ни на проекты, которые используют данный проект.

Получить текущий тип приложения можно посредством метода mxx_screen_mode.

5.10 Указание исходных файлов

5.10.1 Метод sources_root

По-умолчанию, Mxx_ru считает, что имена исходных файлов задаются относительно того каталога, в котором находится файл-проект. Т.е., если в качестве пседвдонима проекта указано имя interface/prj.rb, то конструкция:


1  c_source( "main.c" )
2  cpp_source( "io.cpp" )

приведет к тому, что Mxx_ru будет искать файлы interface/main.c и interface/io.cpp. Такой подход позволяет легко перечислять в проектном файле содержимое небольшого проекта. Но может быть два случая, когда требуется указать Mxx_ru иное место для поиска исходных файлов:

  1. Когда исходные тексты расположены в другой ветви файловой структуры проекта, нежели проектный файл. Например, все проектные файлы сложного проекта находятся в каталоге mxxru_prjs, а исходные файлы в подкаталоге src3. Тогда следует использовать метод sources_root с одним параметром:


    1  Mxx_ru::Cpp::Exe_target.new( "mxxru_prjs/interface.rb" ) {
    2   ...
    3   sources_root( "src/interface" )
    4  
    5   c_source( "main.c" )
    6   cpp_source( "io.cpp" )
    7   ...
    8  }
  2. Когда файловая структура проекта имеет большую глубину. В этом случае неудобно для каждого исходного файла указывать полный путь к нему. В таких случаях можно воспользоваться вызовом метода sources_root с двумя параметрами: именем каталога и блоком кода. В этом случае метод sources_root работает очень просто: он конкатенирует текущее значение параметра sources_root с первым аргументом и получившийся результат устанавливается в качестве нового значения параметра sources_root. Затем метод sources_root запускает переданный ему блок кода, а по завершению блока кода восстанавливает значение sources_root в исходное. Причем такое поведение позволяет использовать вызовы sources_root внутри блока-параметра:


    1  Mxx_ru::Cpp::Dll_target.new( "oess_1/db/prj.rb" ) {
    2   ...
    3   sources_root( "impl" ) {
    4   # Для файлов из каталога oess_1/db/impl.
    5   ...
    6   sources_root( "storage" ) {
    7   # Для файлов из каталога oess_1/db/impl/storage.
    8   ...
    9   sources_root( "impl" ) {
    10   # Для файлов из каталога oess_1/db/impl/storage/impl.
    11   ...
    12   }
    13   }
    14   }
    15   sources_root( "site" ) {
    16   # Для файлов из каталога oess_1/db/site.
    17   ...
    18   sources_root( "impl" ) {
    19   # Для файлов из каталога oess_1/db/site/impl.
    20   ...
    21   }
    22   }
    23   ...
    24  }

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


1  Mxx_ru::Cpp::Exe_target.new( "mxxru_prjs/interface.rb" ) {
2   sources_root( "src/interface" )
3  
4   # Эти файлы из каталога src/interface.
5   c_source( "main.c" )
6   cpp_source( "io.cpp" )
7  
8   sources_root( "debug" ) {
9   # Эти файлы из каталога src/interface/debug.
10   cpp_sources( "io_dumper.cpp" )
11   ...
12   }
13   ...
14  }

5.10.2 Методы c_source, cpp_source

Методы c_source и cpp_source предназначены для указания имен C и C++ файлов, входящих в проект. Важно, чтобы файлы, которые содержат только C-код (как правило, имеющие расширение .c) перечислялись с помощью метода c_source, а файлы с C++-кодом (которые на разных платформах могут иметь расширения .C, .cc, .cp, .cpp, .cxx, .c++ и т.д.) перечислялись с помощью метода cpp_source. Дело в том, что на некоторых платформах от типа файла зависит имя используемого компилятра (например, gcc и g++ для GNU C++). На некоторых платформах есть возможность выставлять специальные ключи компилятору для того, чтобы компилятор воспринимал файл как C- или C++-код вне зависимости от расширения файла. Mxx_ru учитывает все эти особенности и активно их использует.

Методы c_source, cpp_source получают два аргумента: первый, обязательный, указывает имя исходного файла. Второй, не обязательный, может содержать опции компилятора, которые будут добавлены к выбранным Mxx_ru опциям при компиляции только этого файла.

Как правило, используется вариант с одним параметром:


1  Mxx_ru::setup_target(
2   Mxx_ru::Cpp::Dll_target.new( "oess_1/io/prj.rb" ) {
3  
4   required_prj( "oess_1/defs/prj.rb" )
5  
6   Oess_1::setup_platform( self )
7  
8   target( "oess_io" + Oess_1::VERSION )
9  
10   define( "OESS_1__IO__PRJ" )
11  
12   cpp_source( "stream.cpp" )
13   cpp_source( "binstream.cpp" )
14   cpp_source( "binbuffer.cpp" )
15   cpp_source( "subbinstream.cpp" )
16   cpp_source( "mem_buf.cpp" )
17   cpp_source( "fixed_mem_buf.cpp" )
18   cpp_source( "bstring_buf.cpp" )
19   }
20  )

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


1  ...
2  cpp_source( "interface.cpp", [ "-DLOG_LEVEL=3" ] )
3  cpp_source( "engine.cpp" )
4  ...

в этом случае символ препроцессора LOG_LEVEL будет определен только при компиляции interface.cpp, но не будет определен для engine.cpp.

Применять методы c_source, cpp_source следует с осторожностью, учитывая следующие факторы:

5.10.3 Метод mswin_rc_file

Метод mswin_rc_file позволяет установить имя ресурсного файла на платформе mswin. Если имя ресурсного файла установлено, то при компиляции проекта Mxx_ru запускает компилятор ресурсов для получения .res файла, а при линковке результирующего exe- или dll-файла использует соответствующее средства toolset-а для включения скомпилированных ресурсов в результирующий файл.

Метод mswin_rc_file получает два параметра: первый, обязательный, указывает имя .rc-файла. Второй, необязательный, может содержать имена файлов, от которых зависит ресурсный файл. Например, имена файлов .ico, .bmp и т.д.

При использовании метода mswin_rc_file необходимо помнить, что значение первого параметра (имени .rc-файла) вычисляется с учетом текущего значения sources_root. Но имена зависимостей, которые передаются во втором параметре, должны быть указаны полностью.

Пример:


1  Mxx_ru::Cpp::Exe_target.new( "interface/prj.rb" ) {
2   ...
3   screen_mode( Mxx_ru::Cpp::SCREEN_WINDOW )
4   ...
5   mswin_rc_file( "resources.rc",
6   [ "interface/res/mainframe.ico",
7   "interface/res/document.ico",
8   "interface/res/toolbar.bmp",
9   "interface/res/reources.rc2" ] )
10   ...
11  }

Примечание. Значение, установленное методом mswin_rc_file учитывается только, если целевой платформой является mswin.

5.11 Указание дополнительных объектных файлов

Метод obj_file позволяет указать проекту дополнительные объектные файлы для линковки результирующего файла. По-умолчанию, Mxx_ru формирует имена объектных файлов, получаемых в результате компиляции исходных файлов, и использует их имена при линковании. Если проекту требуется включить в проект уже готовый объектный файл (например, получаемый путем компиляции исходного файла на другом языке программирования), то имя этого объектного файла нужно включить с помощью метода obj_file. Например:


1  Mxx_ru::Cpp::Exe_target.new( "interface/prj.rb" ) {
2   ...
3   required_prj( "interface/asm/fast_transform/prj.rb" )
4   ...
5   obj_file( "interface/asm/fast_transform/linear.obj" )
6   ...
7  }

Сам Mxx_ru использует метод obj_file в реализации toolset для сохранения в проекте имен объектных файлов, получаемых в результате компиляции исходных файлов.

5.12 Указание дополнительных библиотек

Метод lib позволяет указать проекту дополнительные библиотеки для линкования результирующего файла. По-умолчанию, Mxx_ru извлекает имена необходимых для линкования библиотек из подпроектов. Но часто бывает необходимо указать проекту имя конкретной, как правило, платформо-зависимой библиотеки. В этом случае следует использовать метод lib:


1  Mxx_ru::Cpp::Dll_target.new( "engine/prj.rb" ) {
2   ...
3   if "mswin" == toolset.tag( "target_os" )
4   lib( "winsock.lib" )
5   elsif "unix" == toolset.tag( "target_os" )
6   lib( "socket" )
7   if "bsd" != toolset.tag( "unix_port" )
8   lib( "pthread" )
9   end
10   end
11   ...
12  }

Метод lib получает два аргумента. Первый задает имя библиотеки в том виде, в каком это имя следует указать линкеру в командной строке. Т.е., на платформе mswin это должно быть имя с расширением. А на платформах unix — имя без расширения и префикса lib.

Второй аргумент метода lib задает путь, в котором линкеру следует искать библиотеку. По-умолчанию, этот аргумент равен nil, т.е. линкеру не дается никаких указаний. В этом случае линкер будет искать библиотеку в стандартных для конкретной платформы путях. Если же второй параметр отличен он nil, то указанное значение будет передано линкеру в качестве пути для поиска библиотек. Например, если на платформе unix требуется указать линкеру использовать библиотеку /usr/local/share/mysec/lib/libtdes.3.4.a, то следует вызвать метод lib следующим образом:


1  lib( "tdes.3.4", "/usr/local/share/mysec/lib" )

5.13 Указание режима оптимизации

Метод optimization позволяет установить необходимый режим оптимизации. Mxx_ru учитывает режим оптимизации при формировании опций компилятора в режиме release (см.  5.1.5 на стр.  55). По-умолчанию, используется оптимизации по скорости выполнения сгенерированного кода.

Режим оптимизации задается константами: Mxx_ru::Cpp::OPTIM_SIZE (оптимизация по размеру генерируемого кода) и Mxx_ru::Cpp::OPTIM_SPEED (оптимизации по скорости генерируемого кода).

Режим оптимизации является локальным для проекта параметром. Установленное в проекте значение режима оптимизации не оказывает никакого воздействия ни на подчиненные проекты, ни на проекты, которые используют в качестве подчиненного данный проект.

5.14 Функции для работы с локальными, распространяемыми и глобальными параметрами

Как показано в  5.1.6 на стр.  56, для установки локальных, распространяемых и глобальных параметров проекта используются функции вида:


  <параметр>( a_value, a_type )
  global_<параметр>( a_value )

где <параметр> — это название параметра. Функция первого вида используется для установки локального или распространяемого параметра. Значение параметра будет локальным, если параметр a_type будет иметь значение Mxx_ru::Cpp::Target::OPT_LOCAL, либо будет опущен. Если параметр a_type будет иметь значение Mxx_ru::Cpp::Target::OPT_UPSPREAD, то значение параметра будет автоматически распространяться и на все использующие данный проект проекты. Функция с префиксом global_ используется для установки глобального значения параметра.

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

5.14.1 include_path, global_include_path

Функции include_path, global_include_path позволяют установить пути, в которых компилятор будет искать заголовочные файлы.

5.14.2 define, global_define

Функции define, global_define позволяют установить символы препроцессора, которые будут определены при компиляции исходных C- и C++-файлов.

5.14.3 compiler_option, global_compiler_option

Функции compiler_option, global_compiler_option позволяют задать дополнительные опции компилятора, которые будут использоваться как для компиляции C, так и для компиляции C++-файлов.

5.14.4 c_compiler_option, global_c_compiler_option

Функции c_compiler_option, global_c_compiler_option позволяют задать дополнительные опции компилятора, которые будут использоваться для компиляции только C-файлов.

5.14.5 cpp_compiler_option, global_cpp_compiler_option

Функции cpp_compiler_option, global_cpp_compiler_option позволяют задать дополнительные опции компилятора, которые будут использоваться для компиляции только C++-файлов.

5.14.6 linker_option, global_linker_option

Функции linker_option, global_linker_option позволяют задать дополнительные опции линкера, которые будут использоваться для линковки exe- и dll-файлов.

5.14.7 librarian_option, global_librarian_option

Функции librarian_option, global_librarian_option позволяют задать дополнительные опции библиотекаря, которые будут использоваться для создания статических библиотек.

5.14.8 Компилятор ресурсов на платформе mswin

mswin_rc_include_path, global_mswin_rc_include_path

Функции mswin_rc_include_path, global_mswin_rc_include_path позволяют задать пути поиска заголовочных файлов для компилятора ресурсов.

mswin_rc_define, global_mswin_rc_define

Функции mswin_rc_define, global_mswin_rc_define позволяют задать символы препроцессора, которые будут определены при компиляции ресурсов.

mswin_rc_option, global_mswin_rc_option

Функции mswin_rc_option, global_mswin_rc_option позволяют задать дополнительные опции компилятору ресурсов.

mswin_rlink_option, global_mswin_rlink_option

Функции mswin_rlink_option, global_mswin_rlink_option позволяют задать дополнительные опции линкеру ресурсов.

Hosted by uCoz