Предположим, у меня есть файл SConstruct
, который выглядит следующим образом :
env = Environment()
env.Program("a", ["a.c", "util.c"])
env.Program("b", ["b.c", "util.c"])
Эта сборка работает правильно, без предупреждений SCons. Однако, если я изменю это так, чтобы указать различных библиотек для каждой программы
сборки (фактические библиотеки не имеют отношения):
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
Это похоже на вызывается компоновщиком программ
, автоматически создающим новую среду для сборки исходных текстов , даже если отличается только переменная 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
из предыдущей проприетарной системы сборки, используя написанный мной сценарий преобразования. SCons выдает около 450 предупреждающих сообщений «Две разные среды» для полной сборки с использованием моего текущего SConstruct
.
Я нашел обходной путь, который не включает создание дополнительных переменных для хранения узлов объектного файла:
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 компилирует источник только один раз.
Создание статической библиотеки из первого набора файлов и связывание библиотеки со следующим набором файлов (которые имеют некоторые файлы, общие с первым набором) для создания цели также работает.
env.StaticLibrary ("a", ["a.c","util.c"], LIBS = "m")
env.Program ("b", ["b.c","util.c"], LIBS = ["c","a"])
Вы можете использовать функцию 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")
Объектные файлы создаются только один раз и могут использоваться в нескольких сборках. Надеюсь, это поможет ...