假设我有一个SConstruct
文件,如下所示:
env = Environment()
env.Program("a", ["a.c", "util.c"])
env.Program("b", ["b.c", "util.c"])
此版本正常运行,没有SCons警告消息。但是,如果我修改它以为每个Program
构建指定不同的库(实际库不相关):
env.Program("a", ["a.c", "util.c"], LIBS="m")
env.Program("b", ["b.c", "util.c"], LIBS="c")
然后我收到警告:
scons: warning: Two different environments were specified for target util.o, but they appear to have the same action: $CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES
这似乎是由Program
构建器自动创建用于构建源的新环境引起的,即使它只是LIBS
变量不同(并且所以只有 link 步骤需要有不同的环境)。我可以通过以下方式来解决这个问题:
util = env.Object("util.c")
env.Program("a", ["a.c"] + util, LIBS="m")
env.Program("b", ["b.c"] + util, LIBS="c")
这使用单个Object
构建器来构建util.c
,然后在每个Program
构建中使用预编译的目标文件,从而避免警告。但是,这不应该是必要的。有没有更优雅的方法来解决这个问题?或者这实际上是SCons中应该修复的错误吗?
上下文:我将近2000个C源文件编译成大约20个库和120个具有大量共享源的可执行文件。我使用我编写的转换脚本从以前的专有构建系统创建了SConstruct
文件。 SCons使用我当前的SConstruct
生成了大约450个“两个不同的环境”警告消息,用于完整构建。
答案 0 :(得分:19)
我找到了一种解决方法,它不涉及创建额外的变量来保存目标文件节点:
env.Program("a", ["a.c", env.Object("util.c")], LIBS="m")
env.Program("b", ["b.c", env.Object("util.c")], LIBS="c")
这会在单个环境中隔离util.c
的构建。尽管指定了两次,每次Program
一次,SCons不会对此发出警告,因为它是使用相同env
对象构建的相同源。当然,在这种情况下,SCons只会编译一次源。
答案 1 :(得分:9)
您可以使用Split函数和自定义帮助程序来简化大型项目的构建过程:
def create_objs(SRCS, path=""):
return [env.Object(path+src+".cpp") for src in SRCS]
prg1 = Split("file_1 file_2 file_N")
prg2 = Split("file_2 file_5 file_8")
env.Program("a", create_objs(prg1), LIBS="x")
env.Program("b", create_objs(prg2), LIBS="y")
目标文件只创建一次,它们可以在多个构建中使用。希望这会有所帮助...
答案 2 :(得分:1)
我在代码中发现的一个问题是我没有正确使用目标对象路径。或者换句话说,我有一个变量dir指令,但我没有使用BUILDPATH,而是使用了我原来的源代码路径。这样Scons就会找到在目标BUILDPATH和源路径中生成的对象。
答案 3 :(得分:1)
从第一组文件中创建静态库并将库链接到下一组文件(其中包含与第一组文件共有的一些文件)以创建目标。
env.StaticLibrary ("a", ["a.c","util.c"], LIBS = "m")
env.Program ("b", ["b.c","util.c"], LIBS = ["c","a"])