Как работать "scons: warning: для целевой цели были определены две разные среды"
Предположим, что у меня есть файл 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
, которая отличается (и поэтому только шаг ссылки должен иметь другую среду). Я могу обойти это, сделав что-то вроде:
util = env.Object("util.c")
env.Program("a", ["a.c"] + util, LIBS="m")
env.Program("b", ["b.c"] + util, LIBS="c")
Для построения util.c
используется один конструктор Object
, а затем с использованием предварительно скомпилированного объектного файла в каждой сборки Program
, тем самым избегая предупреждения. Однако это не обязательно. Есть ли более элегантный способ обойти эту проблему? Или это на самом деле ошибка в SCons, которая должна быть исправлена?
Контекст: у меня есть почти 2000 исходных файлов C, скомпилированных в 20 библиотек и 120 исполняемых файлов с большим количеством общих источников. Я создал файл SConstruct
из предыдущей проприетарной системы сборки, используя преобразование script, которое я написал. Существует около 450 предупреждающих сообщений "Две разные среды", созданных SCons для полной сборки с использованием текущего SConstruct
.
Ответы
Ответ 1
Я нашел обходное решение, которое не связано с созданием дополнительных переменных для хранения узлов объектного файла:
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 только компилирует источник один раз в этом случае.
Ответ 2
Вы можете использовать функцию 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")
Объектные файлы создаются только один раз, и их можно использовать в нескольких сборках. Надеюсь, это поможет...
Ответ 3
Одна из проблем, которые я обнаружил в своем коде, заключалась в том, что я неправильно использовал путь к целевому объекту. Или в других словах у меня была директива dir варианта, но вместо использования BUILDPATH я закончил использование моего исходного кода исходного кода. Таким образом, Scons находил объект, сгенерированный в целевом BUILDPATH и исходном пути.