Build-Systeme Teil 3: SCons
-
nash35 schrieb:
Frage, muss man bei SCons noch irgendwas angeben einen Pfad zum compiler(habe VC 2005) oder so?
so richtig hab ich das mit der idee von scons nämlich noch nicht geblick..SCons zieht sich den Pfad zum Visual C++ Compiler normalerweise aus den Umgebungsvariablen. Funktioniert denn dies nicht?
-
nun ja ich möchte ein projekt mit scons kompilieren:
D:\Programmierung\Reflex>scons
scons: Reading SConscript files ...
ValueError: list.remove(x): x not in list:
File "D:\Programmierung\Reflex\SConstruct", line 18:
'python/SConscript'])
File "D:\Programmierung\Python25\scons-0.97\SCons\Script\SConscript.py", line
583:
return apply(method, args, kw)
File "D:\Programmierung\Python25\scons-0.97\SCons\Script\SConscript.py", line
520:
return apply(_SConscript, [self.fs,] + files, subst_kw)
File "D:\Programmierung\Python25\scons-0.97\SCons\Script\SConscript.py", line
245:
exec _file_ in call_stack[-1].globals
File "D:\Programmierung\Reflex\python\SConscript", line 58:
py_files.remove('./genreflex/genreflex-rootcint.py')
D:\Programmierung\Reflex>und das kommt dabei raus?
hat jemand vielleicht ein anderes test projekt das ich kompilieren kann?
-
Gib bitte mal den Inhalt der SConstruct an.
-
es handelt sich dabei um das Projekt hier
http://seal-reflex.web.cern.ch/seal-reflex/download.htmlund das ist der inhalt der SConstruct
from os import curdir from os.path import realpath opts = Options('custom.py') opts.Add(BoolOption ('test', 'Set to 1 if tests shall be compiled', 0)) opts.Add(PathOption ('prefix', 'The installation directory of Reflex', realpath(curdir))) opts.Add(PackageOption('gccxml', 'The >binary< directory of gccxml', 'no')) opts.Add(PackageOption('cppunit', 'The >root< directory of CppUnit', 'no')) env = Environment(options=opts) Export('env') Help(opts.GenerateHelpText(env)) SConscript(['src/SConscript', 'inc/SConscript', 'python/SConscript']) if env['test'] : SConscript('test/SConscript') env.Alias('install', env['prefix'])
-
ihr könnt wohl auch nix damit anfangen, gell?
mhm ich hab an den Entwickler geschrieben, mal sehen was der dazu sagt.
-
nash35 schrieb:
ihr könnt wohl auch nix damit anfangen, gell?
Ne, ehrlich gesagt nicht.
-
Weiß jemand wie ich am einfachsten in verschiedenen *.in Dateien @VERSION@ durch eine Version ersetzen kann? Ich mach es jetzt so:
import os version = "0.6.9" #Replace @VERSION@ in certain files files = ["jngl.pc.in", "autopackage/default.apspec.in"] for filename in files: newfilename = filename.replace(".in", "") t = Command(newfilename, filename, "sed 's/@VERSION@/" + version + "/g' $SOURCE > $TARGET") Clean(t, newfilename) # Make sure scons -c does clean up tidily
Nur das geht leider nur unter Linux (wegen dem sed-Befehl). Da muss es doch aus was vorgefertiges geben, oder?
-
Ich hoffe ich bin hier richtig, oder sollte man zu Fragen doch lieber einen eigenen Thread auf machen?
Naja, zu meiner Frage. Und zwar löst SCons bei mir die Abhängigkeiten nicht richtig auf. Ich hab hier ein Projekt welches aus fünf Unterprojekten besteht. Vier dieser Unterprojekte erstellen jeweils eine statische Bibliothek und das fünfte Projekt (eine Binärdatei) bindet diese Biblotheken alle ein. Im Rootverzeichnis habe ich eine SConstruct Datei und in den Build-Verzeichnissen der Unterprojekte jeweils eine SConscript Datei.
Solange ich nur die 4 Bibliotheken erstellen lasse funktioniert auch alles wunderbar. Aber sobald ich das Projekt mit der Binärdatei, welche die Bibliotheken einbindet, mit aufnehmen kommt SCons aus dem Tritt. Es kompiliert nämlich das Projekt mit der Binärdatei einfach zwischen durch obwohl die Projekte mit den Bibliotheken noch gar nicht alle fertig sind. Logisch dass er dann die Binärdatei nicht gescheit linken kann wenn noch nicht alle Bibliotheken fertig sind.
Ich habe allerdings versucht meine SConstruct und SConscript Datei so portabel wie möglich zu gestalten damit man diese ohne viele verändern zu müssen auch in anderen Projekten verwenden kann. Evtl. ist mir dort ein grober Schnitzer unterlaufen. Hier mal meine Dateien:
SConstruct:
# Projekte (Verzeichnisse) angeben in der Reihenfolge ihrer Abhaengigkeiten. # Das erste Projekt ist das unabhaengigste. # ["<Projektverzeichnis>", "<Verzeichnis in dem das SConscript liegt>"] projects = [["lib1","/build"], ["lib2", "/build"], ["lib3", "/build"], ["lib4", "/build"], ["binary", ""]] # Ab hier muss nichts mehr veraender werden print "===================={ Beginne Buildvorgang }====================" print "Projekte:" for project, build_dir in projects: print "* " + project print "" projectList = "" for project, build_dir in projects: projectList += project + build_dir + "/SConscript " SConscript(Split(projectList))
SCon\1:
from scons_utils import * # ==============={ Projektspezifische Einstellungen }=============== # Die Dateiendung der Sourcecodedateien (z.B. *.cpp fuer C++) SOURCE_EXTENSION = ".cpp" # Der Name des zu erstellenden OUTPUT_NAME = "lib1" # Verzeichnis in welches das fertige Kompilat hinterlegt werden soll # (inkl. eventueller temporaerer Zwischendateien (z.B. *.obj)) BUILD_DIR = "../build" # Verzeichnis in dem die Sourcecodedateien liegen (normal "../src") # Ein einfaches "." geht leider nicht weil damit die Funktion getSourceFiles() nicht klar kommt SRC_DIR = "../src" # Verzeichnis in dem die Headerdateien liegen (normal "../include") INCLUDE_DIR = "../include" # Pfad zu den Bibliotheken LIB_PATH = "" # Benoetigte Bibliotheken LIBS = "" # Typ des zu erstellenden Projekts # OutputTypeEnum.bin(): Binaerdatei # OutputTypeEnum.staticlib(): Statische Bibliothek (z.B. *.lib) # OutputTypeEnum.sharedlib(): Dynamische Bibliothek (z.B. *.dll) OUTPUT_TYPE = OutputTypeEnum.staticlib() # ================================================================== # Buildprozess. Hier muss eigentlich nichts veraendert werden. env = Environment() env.BuildDir(BUILD_DIR, SRC_DIR, duplicate=0) src_files = getSourceFiles(SRC_DIR, SOURCE_EXTENSION) src_files = Split(src_files) for i in range(0, len(src_files)): src_files[i] = BUILD_DIR + "/" + src_files[i] objects = Object(src_files, CPPPATH = INCLUDE_DIR) if OUTPUT_TYPE == OutputTypeEnum.bin(): env.Program(OUTPUT_NAME, objects, LIBS = LIBS, LIBPATH = LIB_PATH) elif OUTPUT_TYPE == OutputTypeEnum.staticlib(): env.StaticLibrary(OUTPUT_NAME, objects, LIBS = LIBS, LIBPATH = LIB_PATH) elif OUTPUT_TYPE == OutputTypeEnum.sharedlib(): env.SharedLibrary(OUTPUT_NAME, objects, LIBS = LIBS, LIBPATH = LIB_PATH)
scons_utils.py:
import os, string # Rekursives durchsuchen eines Verzeichnisses nach allen Sourcefiles. # Durch die Rekursion werden alle Unterverzeichnisse mit druchsucht. def getSourceFiles(dir, src_ext, subpath = ""): srcFiles = "" for node in os.listdir(dir): path = dir + "/" + node if node.endswith(src_ext): srcFiles += subpath + node + " " elif os.path.isdir(path): subpath += node + "/" srcFiles += getSourceFiles(path, src_ext, subpath) return srcFiles # Enumeration fuer den Output-Typ # bin(): Binary (z.B. *.exe) # staticlib(): Statische Bibliothek (z.B. *.lib) # sharedlib(): Dynamische Bibliothek (z.B. *.dll) class OutputTypeEnum: @staticmethod def bin(): return "bin" @staticmethod def staticlib(): return "staticlib" @staticmethod def sharedlib(): return "sharedlib"
Die scons_utils.py habe ich geschrieben um ein paar Dinge zu erleichtern, aber ich denke das ist alles selbsterklärend. Ich hoffe die Länge der Dateien ist nicht zu abschreckend
Bei der SConscript Datei für das Binary werden zusätzlich halt noch die Bibliotheken bei der LIBS-Variablen mit angegeben.
-
Ehrlich gesagt weiß ich nicht, wie man dein Problem SCons-intern beheben kann, da SCons ja keine Reihenfolge für die Builds definiert... außer per Depends-Funktion, aber das ist nicht so das richtige Mittel.
Ich würde einfach ein Skript schreiben, welches zuerst die vier Libs baut und dann die binary.
-
Danke für die Antwort.
Wenn es wirklich nicht anders geht werd ich das wohl tun müssen, auch wenn ich stark gehoft habe dass genau diese Arbeit auch intelligent von SCons erledigt wird. Gerade der fünfte Beitrag von __HIRSCH_H__ hat sich in meinen Ohren nämlich so angehört als wenn in seinem Projekt der "Buildaufbau" sehr ähnlich ist wie in meinem Projekt (wenn nicht sogar noch komplexer) und SCons die Abhängigkeiten unter den verschiedenen Biblotheken aufdröseln könnte und genau weiß was es zuerst kompilieren muss.
-
BugJoe schrieb:
Danke für die Antwort.
Wenn es wirklich nicht anders geht werd ich das wohl tun müssen, auch wenn ich stark gehoft habe dass genau diese Arbeit auch intelligent von SCons erledigt wird. Gerade der fünfte Beitrag von __HIRSCH_H__ hat sich in meinen Ohren nämlich so angehört als wenn in seinem Projekt der "Buildaufbau" sehr ähnlich ist wie in meinem Projekt (wenn nicht sogar noch komplexer) und SCons die Abhängigkeiten unter den verschiedenen Biblotheken aufdröseln könnte und genau weiß was es zuerst kompilieren muss.
Wenn ich mehrere voneinander abhängige Bibliotheken oder Programme baue, mach ich das meistens so, dass ich den Rückgabewert der SharedLibrary Funktion an die entsprechende Program oder SharedLibrary Funktion der abhängigen Bibliothek übergebe.
Beispiel:lib1 = SharedLibrary(myFiles) lib2 = SharedLibrary([otherFiles, lib1]) prog = Program([moreFiles, lib2])
Dann bestimmt scons die Abhängigkeit korrekt.
Tip: Du kannst die lib/prog objekte aus den Unterverzeichnissen mit Return('lib1') zurückgeben.Ich hoffe es hilft dir weiter und du kannst das Konzept in deinen generischen Ansatz einbauen. Wenn ich scons scripte schreibe sind die eigentlich immer massgeschneidert und ziemlich naiv runtergehackt (KISS-Prinzip).
-
Ja, vielen Dank für die Antwort. Werd ich morgen gleich mal ausprobieren. Aber das hört sich sehr gut an
-
Sehr schöner Artikel.
Aber ich hab ein Problem mit boost und CheckCXXHeader() vielleicht hat von euch einer eine Idee, meine bisherige google-Suche war nicht erfolgreich.
if not conf.CheckCXXHeader('boost/test/unit_test.hpp'): print 'Could not find boost/test/unit_test.hpp . Please install boost (www.boost.org)' Exit(1)
Boost ist installiert und die Header liegen auch unter /usr/include/boost/... wenn man das Exit(1) raus nimmt kompiliert auch alles.
Was ist falsch an der Prüfung, bzw. was mache ich falsch an der Stelle?
Muss ich noch die System-Include-Verzeichnisse irgendwo angeben?Danke
-
Was steht denn in der Datei
config.log
? Da sollte drinstehen welches Kommando aufgerufen wurde und welche Fehlermeldung zum Abbruch geführt hat.
-
Merkwürdigerweise versuchte er eine Datei zu kompilieren innerhalb der Tests die nicht existierte. Die temporären Dateien und Verzeichnisse von scons löschen, danach neu ausführen und es ging.
Versteh ich zwar nicht aber Danke