如何解决"scons: warning: Two different environments were specified for target"问题

29

假设我有一个看起来像这样的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: 警告:为目标util.o指定了两个不同的环境,
        但它们看起来有相同的操作:$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES

这似乎是由于Program构建器自动为构建源文件创建了一个新的环境,即使只有LIBS变量不同(因此只需要在链接步骤中使用不同的环境)。我可以通过执行以下操作解决此问题:

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文件。 对于当前的SConstruct进行完整构建时,SCons会产生大约450个“两个不同环境”警告消息。

4个回答

20
我找到了一个解决方法,它不涉及创建额外的变量来保存对象文件节点:
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只编译一次源代码。


10
您可以使用 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")

对象文件只需创建一次,可以在多个构建中使用。希望这有所帮助...


我投票支持这个解决方案,因为它不需要我记住每个对象编译到哪个环境中。所有对象都编译到一个单一的环境中。它还允许SConscript文件保持干净。我修改了create_obj函数,不再自动附加.cpp后缀。 - Be Kind To New Users

1
将第一组文件创建为静态库,然后将该库链接到下一组文件(其中一些文件与第一组文件有共同之处),以创建目标也是可行的。
env.StaticLibrary ("a", ["a.c","util.c"], LIBS = "m")
env.Program ("b", ["b.c","util.c"], LIBS = ["c","a"])

1
我在代码中发现的一个问题是我没有正确使用目标对象路径。换句话说,我有一个变量目录指令,但我没有使用BUILDPATH,而是使用了原始源代码路径。这样Scons就会在目标BUILDPATH和源路径中找到生成的对象。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接