piątek, 17 czerwca 2011

SCons i kompilacja kodu w standardzie C++0x

Krótko o SConsie
SCons to ciekawe narzędzie do kompilacji kodu C++, Javy czy LaTeX'a. Autorzy chwalą się pisząc nieskromnie: next-generation build tool.
Kompilacja prostego programu w C++ wygląda następująco:
  1. Tworzymy plik SConstruct
  2. Uruchamiamy polecenie scons
# plik: SConstruct
Program('game', 'main.cpp')   # pierwszy argument można pominąć
Jest to równoważne uruchomieniu następujących poleceń:
g++ -o main.o -c main.cpp
g++ -o game main.o
Łatwo możemy także tworzyć biblioteki:
# plik: SConstruct
SharedLibrary('superlib', 'superlib.cpp')
Jest to równoważne:
g++ -o superlib.os -c -fPIC superlib.cpp
g++ -o libsuperlib.so -shared superlib.os
Widzimy, że SCons zadbał o odpowiednie flagi oraz prefix lib- dla nazwy pliku wynikowego.

Ręczne tworzenie bardziej skomplikowanych poleceń może wyglądać np. tak:
env = Environment()
env.MergeFlags("-lSDL -lSDL_mixer -lSDL_image -lGL -lGLU")
env.MergeFlags("-g -ggdb")
env.MergeFlags("-W -Wall -Wextra -Woverloaded-virtual -pedantic")
env.Program("game", Glob("*.cpp") + Glob("editor/*.cpp"))
Jeżeli nie chcemy wpisywać minusów przed nazwą bibliotek (co prawdopodobnie jest także zachowaniem przeciw wieloplatformowości pliku SConstruct), możemy napisać tak:
env.Append(LIBS = Split('SDL SDL_mixer SDL_image GL GLU'))
Dość ciekawy jest fakt, że SCons sam rozpoznaje, które flagi powinny być gdzie użyte. Wpisując
env.MergeFlags("-I /src/include/")
env.MergeFlags("-L /src/lib/")
pierwsza flaga zostanie użyta podczas kompilacji, a druga dopiero podczas łączenia (konsolidacji).

Konkretnie o problemie

Wydaje się, że odkryliśmy super narzędzie i teraz kompilacja już będzie marzeniem. Rzeczywiście, w prostych przypadkach jest bardzo wygodne. Sprawa trochę się skomplikowała, gdy chciałem dodać flagę zmieniającą używany przez kompilator standard na C++0x.

Po wpisaniu
env.MergeFlags('-std=c++0x')
SCons zachowywał się jakbym niczego nie dopisał! Trochę zaskakujące może być, że komendę
env.MergeFlags('-fmessage-length=70')
wykonał poprawnie (odpowiednia flaga pojawiła się na wyjściu kompilatora).

Rozwiązanie 1
Dodać flagę w definicji środowiska:
env = Environment(CPPFLAGS = ['-std=c++0x'])

Rozwiązanie 2

Zrezygnować z MergeFlags na rzecz Append:
env.Append(CPPFLAGS = '-std=c++0x')

Kompletny SConstruct może wyglądać np. tak:
EnsurePythonVersion(2, 6) 
EnsureSConsVersion(2, 0)

env = Environment()
env.Append(CPPPATH = ['/data/include/boost/', '/usr/include/', ])
env.Append(LIBPATH = [])

env.Append(CPPDEFINES = {'DEBUG_BUILD' : '1'})

env.Append(CPPFLAGS = Split('-W -Wall -Wextra -Woverloaded-virtual -pedantic'))
env.Append(CPPFLAGS = Split('-std=c++0x -g -ggdb'))

env.Append(LIBS = Split('SDL SDL_mixer SDL_image GL GLU'))

env.Program("game", Glob("*.cpp") + Glob("editor/*.cpp") + Glob("gui/*.cpp"))

Brak komentarzy:

Prześlij komentarz