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:
- Tworzymy plik SConstruct
- 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"))