2012-07-17 16 views
5

Estoy teniendo un problema para refactorizar un sistema de compilación basado en scons. Tenemos un árbol fuente C/C++ con varios objetos de salida diferentes (dlls, ejecutables, ejecutables de prueba) y un diseño un tanto heterogéneo para nuestros archivos fuente (aunque la mayoría está en directorios 'module' con directorios src/ y inc/).scons herencia del entorno de construcción

Uno de mis mayores problemas con la configuración actual es que realmente queremos que todos estos productos de compilación se construyan con opciones de compilador consistentes de forma predeterminada. Nuestro diseño actual tiene un archivo master SConstruct que invoca muchos archivos subConscription en subdirectorios que luego compilan piezas de los productos de compilación más grandes (por ejemplo, .a). Por defecto, la función SConscript() en scons no pasa ni hereda el objeto de entorno de construcción actual al archivo llamado SConstruct. Eso significa que actualmente todos esos archivos SConstript secundarios están utilizando sus propios entornos de construcción diferentes.

El nuevo diseño que estoy tratando de armar tiene un entorno de construcción maestro que se ensambla en la raíz del árbol fuente con todos los CFLAGS necesarios y las definiciones de construcción que necesitamos. Me gustaría que este entorno de construcción se transmita a los archivos subConscript para que sepa que cada archivo .c y .cpp en nuestro árbol de compilación se está construyendo con la misma línea de comandos.

No estoy seguro de cómo hacer esto en scons, sin embargo. Están las funciones Import() y Export(), pero esas son básicamente variables globales feas: el archivo SConstruct llamante no tiene mucho control sobre lo que hace el archivo SConstruct secundario con la variable global Export() 'ed. ¿Hay alguna forma limpia de entregar el archivo de subConscript el entorno de construcción actual como parámetro, sin dejar que necesariamente lo modifique? Algo tal vez como:

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 

sé que podría hacer algo torpe y especie de bruto como esto:

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') 

¿Hay una manera elegante de hacer esto?

Actualización:

así que he jugado un poco con esto un poco más, y parece que el tiempo que hago esto en el archivo maestro 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) 

y luego en somelib/SConscript

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

entonces el master_env en el SConstruct principal se deja sin contaminar. Era importante para mí que el Export(env=env.Clone()) funcionara porque no quería confiar en todos los SConscripts secundarios para hacer la seguridad (Clone() 'ing), esa política debería ser archivos SConscript/SConstruct principales.

Aún así, es un poco feo tener que tener env como nombre de parámetro por política.

Respuesta

7

La mejor manera que conozco es de su maestro SConstruct acaba de hacer esto:

env = Environment() 

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

Luego, en el fichero src/SConscript:

Import('env') 

A continuación, se puede hacer referencia a la variable de entorno como lo haría en su archivo SConstruct. Si no desea mutar env del SConstruct en src/SConscript, poner esto justo después de la importación:

env = env.Clone() 

bastante seguro de que es todo lo que hay que hacer.

+0

Gracias Tom. Una cosa para agregar: si 'env' no es necesariamente el segundo argumento, se puede usar la sintaxis: 'exports = 'env''. –

+0

Desafortunadamente, esto aún deja la clonación al módulo discreción del niño, por lo que no hay garantía de la siguiente módulo que va a hacer. –

1

Escapé la fuente (Scons 2.1.0 en Ubuntu 12.04) y descubrí que Export actualiza el diccionario global_exports con sus palabras clave.

lo que este código probablemente Run:

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

No hay nada acerca de la documentación, por lo que es una característica.

El Export y SConstript usan magia de marco para obtener una variable por nombre, incluso si puede ser buena para los usuarios que aún no conocen Python, es malvada.

1

La solución presentada por la OP en la actualización tiene un problema grave (probado con scons-2.3.3 y 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) 

uso de lo anterior y encienda CacheDir(some_dir) (también usado VariantDir, en caso de que haya alguna diferencia). En dir1, hacer una construcción completa usando scons --cache-debug=log. Después de la construcción ha terminado, en dir2 con idéntico código, también hacer una construcción completa usando scons --cache-debug=log. Todos los archivos deberían copiarse de la memoria caché de compilación, pero descubrí que la gran mayoría no se copiaba. La mayoría de los archivos, pero no todos, tenían desajustes de firmas MD5 entre los dos directorios. Este problema también puede ser provocada por la modificación de un archivo en 'dir1' y la reconstrucción, a continuación, hacer frente a las modificaciones 'directorio2', y también la reconstrucción. Verá la misma discrepancia MD5.

En este punto, haga un scons -c y luego elimine los archivos .sconsign.dblite en ambos directorios (y elimine la memoria caché de compilación por si acaso). Reconstruya primero en dir1, y cuando eso termine, vuelva a generar en 'dir2'. Obtendrá el comportamiento correcto: las firmas MD5 coincidirán y los archivos se copiarán de la memoria caché de compilación.

que terminó abandonando la solución de la OP, y transferir la responsabilidad de preservar el medio ambiente de los padres a todos los subdirectorios, de acuerdo con la solución de Tom. No es exactamente lo que quería hacer, pero al menos la caché de compilación ahora funciona como se esperaba.

Cuestiones relacionadas