Глава 3
Несколько простых примеров

3.1 Простой exe-файл

Пусть необходимо скомпилировать один C++ файл и получить exe-файл:


1  #include <iostream>
2  #include <string>
3  
4  void
5  say_hello( std::ostream & to )
6    {
7      to << "Hello!" << std::endl;
8    }
9  
10  void
11  say_bye( std::ostream & to )
12    {
13      to << "Bye!" << std::endl;
14    }
15  
16  int
17  main()
18    {
19      say_hello( std::cout );
20  
21      std::cout << "Simple exe main..." << std::endl;
22  
23      say_bye( std::cout );
24  
25      return 0;
26    }

Для этого потребуется следующий Mxx_ru-проектный файл (с именем prj.rb):


1  require ’mxx_ru/cpp’
2  
3  Mxx_ru::setup_target(
4    Mxx_ru::Cpp::Exe_target.new( "prj.rb" ) {
5      target( "simple_exe" )
6  
7      cpp_source( "main.cpp" )
8    }
9  )

Для компиляции проекта необходимо запустить интерпретатор ruby.rb и указать ему имя проектного файла:


  ruby prj.rb

В результате, на платформе mswin будет построен файл simple_exe.exe, а на платформе unix — simple_exe.

3.2 exe-файл и простая статическая библиотека

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

Для статической библиотеки создаются файлы:

Для основного модуля создаются файлы:

Для компиляции всего проекта, включая статическую библиотеку и основной модуль необходимо указать интерпретатору Ruby имя проектного файла prj.rb. Mxx_ru автоматически скомпилирует библиотеку say и слинкует с ней основной модуль.

Необходимо отметить, что в проектном файле prj.rb не делается никаких указаний относительно имени библиотеки say. Более того, основной модуль даже не знает, является ли библиотека статической или динамической. Основной модуль просто указывает, что ему необходим проект, описанный в проектном файле say.rb. За все остальное отвечает Mxx_ru — компиляция подчиненного проекта, определение имени получившейся библиотеки, линкование основного модуля с библиотекой say.

3.3 exe-файл, динамическая и статическая библиотеки

Пусть теперь требуется усложнить два предыдущих примера — требуется создать динамически-загружаемую библиотеку, предоставляющую класс inout_t. Задачей данного класса является печать строки “Hello!” в конструкторе и строки “Bye!” в деструкторе. Объекты класса inout_t можно будет объявлять в функциях для того, чтобы на стандартный поток ошибок печатались сообщения в входе/выходе в/из функции.

Для своей работы библиотека inout будет использовать модифицированный вариант библиотеки say — в функции say_hello, say_bye добавляется еще один аргумент. В результате библиотека say будет состоять из следующих файлов:

Библиотека inout состоит из следующих файлов:

Основной модуль состоит из файлов:

Важно отметить, что основной модуль напрямую зависит только от подпроекта inout. Неявная зависимость основного модуля от библиотеки say отслеживается Mxx_ru. Для таких платформ, как mswin и os2 эта неявная зависимость не столь важна, как на unix-платформах. В частности, при линковании основного модуля на платформах unix нужно будет указывать линкеру не только библиотеку inout, но и библиотеку say. В случае с Mxx_ru основной модуль об этом знать не должен — Mxx_ru в состоянии самостоятельно извлечь из подпроектов всю необходимую информацию и распорядиться ей в зависимости от используемой платформы.

3.4 exe-файл, динамическая, статическая библиотеки и исходные файлы в разных каталогах

В предыдущем примере есть два серьезных недостатка:

  1. Все файлы (заголовочные, исходные, проектные, результаты компиляции и линковки) находятся в одном каталоге. Так, после компиляции проекта g++ на платформе Cygwin в каталоге размещаются следующие файлы:


      exe_dll_lib.exe*
      inout.cpp
      inout.hpp
      inout.rb
      libinout.a
      libinout.so*
      libsay.a
      main.cpp
      o/
      prj.rb
      say.cpp
      say.hpp
      say.rb

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

  2. В каждом из проектных файлов есть инструкция: include_path("."). Было бы удобнее, если бы существовало одно место, в котором можно было бы задать общие для всей группы подпроектов параметры.

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


  /
  |--inout/
  |  |--inout.cpp
  |  |--inout.hpp
  |  ‘--prj.rb
  |--lib/
  |--main/
  |  |--main.cpp
  |  ‘--prj.rb
  |--say/
  |  |--prj.rb
  |  |--say.cpp
  |  ‘--say.hpp
  ‘--build.rb

Каталог lib предназначен для размещения библиотек (статических и библиотек импорта для dll).

3.4.1 Подпроект say

Подпроект say состоит из следующих файлов:

3.4.2 Подпроект inout

Подпроект main состоит из следующих файлов:

3.4.3 Подпроект main

Подпроект main состоит из следующих файлов:

3.4.4 Файл build.rb

Файл build.rb — это специальный проектный файл. Он должен располагаться в корневом каталоге проекта, в том каталоге, из которого запускается интерпретатор Ruby. В файле build.rb должны быть заданы все параметры, глобальные для всего проекта.

Если проект состоит из нескольких подпроектов, как в данном случае, то build.rb как правило, является проектом-композитом.

Для данного примера build.rb имеет вид:


1  require ’mxx_ru/cpp’
2  
3  Mxx_ru::setup_target(
4    Mxx_ru::Cpp::Composite_target.new( Mxx_ru::BUILD_ROOT ) {
5      required_prj( "main/prj.rb" )
6  
7      global_include_path( "." )
8    }
9  )

3.4.5 Компиляция всего проекта

Для компиляции примера необходимо войти в корневой каталог примера (в котором находится файл build.rb) и запустить интерпретатор Ruby с файлом build.rb в качестве параметра. В результате компиляции g++ на платформе Cygwin в корневом каталоге окажутся файлы:


  build.rb
  exe_dll_lib.exe*
  inout/
  lib/
  libinout.so*
  main/
  say/

а в каталоге lib файлы:


  libinout.a
  libsay.a

3.4.6 Компиляция только одного подпроекта

Для компиляции только одного подпроекта необходимо находясь в корневом каталоге примера (т.е. там, где расположен build.rb) запустить интерпретатор Ruby, указав ему имя проектного файла и аргумент --mxx-cpp-1. Например, для компиляции только inout:


  ruby inout/prj.rb --mxx-cpp-1

В этом случае будет обработан только сам подпроект inout без своих подпроектов. Т.е. если подпроект say не был перед этим скомпилирован, то линковка inout завершиться неудачей из-за того, что нет библиотеки say.

3.5 Операция clean

По-умолчанию, Mxx_ru выполняет построение проекта (в случае C/C++ это компиляция и линкование). Но Mxx_ru так же поддерживает и обратную операцию – clean, т.е. удаление всего, что было построено. Для C/C++ операция clean приводит к уничтожению всех объектных файлов, библиотек, исполнимых файлов и других результатов компиляции и линкования.

Для выполнения операции clean необходимо запустить интерпретатор ruby, передать ему имя проектного файла и указать аргумент --mxx-clean:


  ruby build.rb --mxx-clean

Операция clean распространяется как на сам проект, имя проектного файла которого передано Ruby-интерпретатору, так и на все подпроекты. Если для C/C++ проектов необходимо выполнить очистку только одного проекта, без его подпроектов, то интерпретатору Ruby нужно передать имя проектного файла этого проекта и аргументы --mxx-clean, --mxx-cpp-1.


  ruby build.rb --mxx-clean --mxx-cpp-1

Hosted by uCoz