2012-07-17 12 views
5

Mam problem z refaktoryzacją systemu budowy opartego na scons. Mamy drzewo źródłowe C/C++ z kilkoma różnymi obiektami wyjściowymi (biblioteki dll, pliki wykonywalne, pliki wykonywalne testów) i nieco niejednorodny układ dla plików źródłowych (chociaż większość z nich znajduje się w katalogach "module" z katalogami src/ i .scons dziedziczenie środowiska budowlanego

Jednym z moich największych problemów z bieżącą konfiguracją jest to, że naprawdę chcemy, aby wszystkie te produkty kompilacji były budowane z domyślnymi opcjami kompilatora. Nasz obecny układ ma główny plik SConstruct, który wywołuje wiele plików pod-SCONScript w podkatalogach, które następnie budują kawałki większych produktów kompilacji (na przykład .a). Domyślnie funkcja SConscript() w scons nie przekazuje ani nie dziedziczy bieżącego obiektu środowiska konstrukcyjnego do wywoływanego pliku SConstruct. Oznacza to, że obecnie wszystkie z tych plików podskryptów SConstrip używają własnych, różnych środowisk konstrukcyjnych.

Nowy układ, który próbuję zestawić, ma główne środowisko konstrukcyjne, które jest zestawiane razem z korzeniami drzewa źródłowego wraz ze wszystkimi niezbędnymi CFLAGS i wymaganiami kompilacji, których potrzebujemy. Chciałbym, aby to środowisko konstrukcyjne było przekazywane do plików pod-SConscript, dzięki czemu wiem, że każdy plik .c i .cpp w naszym drzewie kompilacji jest budowany za pomocą tego samego wiersza poleceń.

Nie jestem pewien, jak to zrobić w scons. Dostępne są funkcje Import() i , ale są to w zasadzie brzydkie zmienne globalne - wywołujący plik SConstruct nie ma dużej kontroli nad tym, co robi plik podkontekstury ze zmienną globalną, która jest Export() 'wyd. Czy istnieje jakiś czysty sposób, w zasadzie przekazujący plik pod-SConscript do obecnego środowiska konstrukcyjnego jako parametru, bez konieczności modyfikowania go? Coś może podoba:

master_env = Environment() 
master_env.Append(CXXFLAGS=['-Wall', '-Werror', '-g', '-fPIC', ... ]) 

### add other stuff that we want everything to use 

SConscript('somelibrary/SConstruct', inherited_environment=master_env.Clone()) 

### master_env has now been used to build a 
### .dll in somelibrary/, but any variations 
### made to somelibrary/SConstruct's inherited 
### env haven't contaminated master_env 

wiem, że mogę zrobić coś niezgrabne i rodzaju brutto takiego:

clobber_env = Environment() 
master_env = Environment() 
master_env.Append(CXXFLAGS=['-Wall', '-Werror', '-g', '-fPIC', ... ]) 

call_somelibrary_sconstruct(master_env) 

def call_somelibrary_sconstruct(env): 
    param_env = env.Clone() 
    Export('param_env') 
    SConstript('somelibrary/SConstruct') 

    # because we don't want any contamination of our global variable 
    # between SConscript calls. I'm not even sure if this is necessary 
    # or does what I think it does because I'm not sure how this ugly 
    # Export()'d global variable environment works with locals like 
    # param_env here. 
    param_env = clobber_env 
    Export('param_env') 

Czy istnieje elegancki sposób to zrobić?

Aktualizacja:

Więc Grałem około z tym trochę więcej, i wygląda na to tak długo, jak to zrobić w pliku mistrz SConstruct:

def build_somelib(env): 
    Export(env=env.Clone()) 
    somelib = SConscript('somelib/SConscript') 
    return somelib 

master_env = Environment() 
master_env.Append(CXXFLAGS=['-Wall', '-Werror', '-g', '-fPIC', ... ]) 

build_somelib(master_env) 

a potem w somelib/SConscript

Import('env') 
env.Append(CXXFLAGS=['-weirdoption1', ... ]) 
lib = env.StaticLibrary('somelib', source=['source1.cpp', 'source2.cpp', ...]) 
Return("lib") 

następnie master_env w głównym SConstruct pozostało nieskażone. To było dla mnie ważne, że Export(env=env.Clone()) działa, ponieważ nie chciałem polegać na wszystkich pod-SConscriptach, aby wykonać funkcję Clone() bezpieczeństwa - ta zasada powinna być nadrzędnymi plikami SConscript/SConstruct.

Nadal jest trochę brzydko, aby mieć nazwę env jako nazwę parametru według zasad.

Odpowiedz

7

Najlepszym sposobem, wiem to od swojego mistrza SConstruct po prostu to zrobić:

env = Environment() 

env.SConscript('src/SConscript', 'env') 

Następnie w src/SConscript pliku:

Import('env') 

Następnie można odnosić się do zmiennej env jako byłbyś w swoim pliku SConstruct. Jeśli nie chcesz, aby mutować env w SConstruct w src/SConscript, umieścić tego prawa po przywozie:

env = env.Clone() 

pewien, że wszystko jest do niego.

+0

Dzięki Tom. Jedna rzecz do dodania: jeśli "env" niekoniecznie jest drugim argumentem, można użyć składni: "exports = 'env''. –

+0

Niestety, nadal pozostawia to klonowanie do uznania modułu podrzędnego, więc nie ma gwarancji, że następny moduł to zrobi. –

1

I grep źródła (Scons 2.1.0 w Ubuntu 12.04) i dowiedzieć się, że Export zaktualizować słownik ze słowami kluczowymi.

Więc ten kod będzie prawdopodobnie uruchomić:

Export(param_env=env.Clone()) 
SConscript('somelibrary/SConstruct') 
Export(param_env=clobber_env) 

Nie ma nic o w dokumentacji, więc jest to cecha.

Za pomocą ramek magicznych można uzyskać zmienną po nazwie, nawet jeśli może to być dobre dla użytkowników, którzy nie znają jeszcze Pythona, jest to złe.

1

Rozwiązanie przedstawione przez OP aktualizacji ma poważny problem (test z SCons-2.3.3, 2.3.4-SCons):

def build_somelib(env): 
    Export(env=env.Clone()) 
    somelib = SConscript('somelib/SConscript') 
    return somelib 

master_env = Environment() 
master_env.Append(CXXFLAGS=['-Wall', '-Werror', '-g', '-fPIC', ... ]) 

build_somelib(master_env) 

używanie tych związków i włączyć CacheDir(some_dir) (również używał VariantDir, w przypadku, który robi jakąkolwiek różnicę). W dir1 wykonaj pełną kompilację przy użyciu scons --cache-debug=log. Po zakończeniu kompilacji, w dir2 z identycznym kodem, wykonaj także pełną kompilację przy użyciu scons --cache-debug=log. Wszystkie pliki powinny zostać skopiowane z pamięci podręcznej kompilacji, ale okazało się, że zdecydowana większość nie była kopiowana. Większość plików, ale nie wszystkie, zawierała niedopasowania sygnatur MD5 między tymi dwoma katalogami. Ten problem można również uruchomić, modyfikując plik w "dir1" i przebudowując, a następnie modyfikując modyfikacje do "dir2", a także przebudowując. Zobaczysz tę samą niezgodność MD5.

W tym miejscu wykonaj scons -c, a następnie usuń pliki .sconsign.dblite w obu katalogach (i usuń pamięć podręczną kompilacji dla dobrej miary). Przebuduj najpierw w dir1, a kiedy to się skończy, przebuduj w "dir2". Otrzymasz prawidłowe zachowanie: sygnatury MD5 będą pasować, a pliki będą kopiowane z pamięci podręcznej kompilacji.

Porzuciłem rozwiązanie OP i przerzuciłem odpowiedzialność za zachowanie środowiska macierzystego na wszystkie podkatalogi, zgodnie z rozwiązaniem Toma. Nie dokładnie to, co chciałem zrobić, ale przynajmniej pamięć podręczna kompilacji działa teraz zgodnie z oczekiwaniami.

Powiązane problemy