Как получить проекты для размещения вывода сборки в тот же каталог с помощью Scons?
Фон
Я пробовал Scons, создав базовый проект С++, который имеет два подпроекта:
- Prj1 - EXE, который зависит от Prj2
- Prj2 - это DLL, которая экспортирует некоторые функции.
Проблема, с которой я сталкиваюсь, заключается в том, что библиотека создает файлы .obj,.pdb,.lib,.dll и т.д. в том же каталоге, что и файл SConscript, в то время как EXE создает свои файлы в том же каталоге, что и его SConscript. Приложение успешно создает как зависимость Prj2, так и себя. Однако вы не можете запустить полученный EXE, потому что он не может найти нужную библиотеку, потому что он находится в другом каталоге.
Вопрос
Как я могу получить несколько проектов с зависимостями для вывода их двоичных файлов и отладки информации в общий каталог, чтобы их можно было выполнить и отладить?
Потенциальные решения
Это то, о чем я думал до сих пор:
- Я попытался использовать VariantDir (ранее называемый BuildDir), однако это, похоже, не работает. Возможно, я здесь что-то путаю.
- Я мог бы потенциально рассказать компилятору и компоновщику явно (например, через Fo/Fd), куда следует отбрасывать свои файлы (это лучшее или единственное решение???)
- Выполните команду копирования в результирующих двоичных файлах (это кажется взломом и довольно болью для управления/поддержки).
Update
Я обновил структуру и содержимое файла ниже, чтобы полностью отразить рабочее решение. Благодаря скорби о его прозрении.
Command
При такой конфигурации вы должны, к сожалению, выполнить сборку cd'ing в каталоге сборки, а затем выполнить приведенную ниже команду. Мне нужно получить правильную рабочую настройку псевдонима, чтобы обойти это.
build> scons ../bin/project1.exe
Структура файла
/scons-sample
/bin
/release
/debug
/build
SConstruct
scons_helper.py
/prj1
SConscript
/include
/src
main.cpp
/prj2
SConscript
/include
functions.h
/src
functions.cpp
SConstruct
import os.path
BIN_DIR = '../bin'
OBJ_DIR = './obj'
#--------------------------------------
# CxxTest Options
#--------------------------------------
CXXTEST_DIR = '../extern/CxxTest/CxxTest-latest'
PERL = 'perl -w'
TESTS = '*.h'
TESTGEN = PERL + CXXTEST_DIR + '/cxxtestgen.pl'
CXXTESTGEN_FLAGS = '--runner=ParenPrinter \
--abort-on-fail \
--have-eh'
#--------------------------------------
# Options
#--------------------------------------
SetOption( 'implicit_cache', 1 )
# command line options
opts = Options()
opts.AddOptions(
EnumOption(
'debug',
'Debug version (useful for developers only)',
'no',
allowed_values = ('yes', 'no'),
map = { },
ignorecase = 1
)
)
#--------------------------------------
# Environment
#--------------------------------------
env = Environment(
options = opts,
#--------------------------------------
# Linker Options
#--------------------------------------
LIBPATH = [
'../extern/wxWidgets/wxWidgets-latest/lib/vc_dll'
],
LIBS = [
# 'wxmsw28d_core.lib',
# 'wxbase28d.lib',
# 'wxbase28d_odbc.lib',
# 'wxbase28d_net.lib',
'kernel32.lib',
'user32.lib',
'gdi32.lib',
'winspool.lib',
'comdlg32.lib',
'advapi32.lib',
'shell32.lib',
'ole32.lib',
'oleaut32.lib',
'uuid.lib',
'odbc32.lib',
'odbccp32.lib'
],
LINKFLAGS = '/nologo /subsystem:console /incremental:yes /debug /machine:I386',
#--------------------------------------
# Compiler Options
#--------------------------------------
CPPPATH = [
'./include/',
'../extern/wxWidgets/wxWidgets-latest/include',
'../extern/wxWidgets/wxWidgets-latest/vc_dll/mswd'
],
CPPDEFINES = [
'WIN32',
'_DEBUG',
'_CONSOLE',
'_MBCS',
'WXUSINGDLL',
'__WXDEBUG__'
],
CCFLAGS = '/W4 /EHsc /RTC1 /MDd /nologo /Zi /TP /errorReport:prompt'
)
env.Decider( 'MD5-timestamp' ) # For speed, use timestamps for change, followed by MD5
Export( 'env', 'BIN_DIR' ) # Export this environment for use by the SConscript files
#--------------------------------------
# Builders
#--------------------------------------
SConscript( '../prj1/SConscript' )
SConscript( '../prj2/SConscript' )
Default( 'prj1' )
scons_helper.py
import os.path
#--------------------------------------
# Functions
#--------------------------------------
# Prepends the full path information to the output directory so that the build
# files are dropped into the directory specified by trgt rather than in the
# same directory as the SConscript file.
#
# Parameters:
# env - The environment to assign the Program value for
# outdir - The relative path to the location you want the Program binary to be placed
# trgt - The target application name (without extension)
# srcs - The list of source files
# Ref:
# Credit grieve and his local SCons guru for this:
# http://stackoverflow.com/info/279860/how-do-i-get-projects-to-place-their-build-output-into-the-same-directory-with
def PrefixProgram(env, outdir, trgt, srcs):
env.Program(target = os.path.join(outdir, trgt), source = srcs)
# Similar to PrefixProgram above, except for SharedLibrary
def PrefixSharedLibrary(env, outdir, trgt, srcs):
env.SharedLibrary(target = os.path.join(outdir, trgt), source = srcs)
def PrefixFilename(filename, extensions):
return [(filename + ext) for ext in extensions]
# Prefix the source files names with the source directory
def PrefixSources(srcdir, srcs):
return [os.path.join(srcdir, x) for x in srcs]
SConscript для Prj1
import os.path
import sys
sys.path.append( '../build' )
from scons_helper import *
Import( 'env', 'BIN_DIR' ) # Import the common environment
prj1_env = env.Clone() # Clone it so we don't make changes to the global one
#--------------------------------------
# Project Options
#--------------------------------------
PROG = 'project1'
#--------------------------------------
# Header Files
#--------------------------------------
INC_DIR = [
'../prj2/include'
]
HEADERS = [
''
]
#--------------------------------------
# Source Files
#--------------------------------------
SRC_DIR = './src'
SOURCES = [
'main.cpp'
]
# Prefix the source files names with the source directory
SOURCES = PrefixSources( SRC_DIR, SOURCES )
#--------------------------------------
# Compiler and Linker Overrides
#--------------------------------------
prj1_env.Append(
CPPPATH = INC_DIR,
LIBS = 'project2',
LIBPATH = BIN_DIR,
# Microsoft Visual Studio Specific
PDB = os.path.join( BIN_DIR, PROG + '.pdb' )
)
#--------------------------------------
# Builders
#--------------------------------------
PrefixProgram( prj1_env, BIN_DIR, PROG, SOURCES )
SConscript для Prj2
import os.path
import sys
sys.path.append( '../build' )
from scons_helper import *
Import( 'env', 'BIN_DIR' ) # Import the common environment
prj2_env = env.Clone() # Clone it so we don't make changes to the global one
#--------------------------------------
# Project Options
#--------------------------------------
PROG = 'project2'
#--------------------------------------
# Header Files
#--------------------------------------
INC_DIR = [
''
]
HEADERS = [
'functions.h'
]
#--------------------------------------
# Source Files
#--------------------------------------
SRC_DIR = './src/'
SOURCES = [
'functions.cpp'
]
# Prefix the source files names with the source directory
SOURCES = PrefixSources( SRC_DIR, SOURCES )
#--------------------------------------
# Compiler and Linker Overrides
#--------------------------------------
# Update the environment with the project specific information
prj2_env.Append(
CPPPATH = INC_DIR,
# Microsoft Visual Studio Specific
PDB = os.path.join( BIN_DIR, PROG + '.pdb' )
)
#--------------------------------------
# Builders
#--------------------------------------
PrefixSharedLibrary( prj2_env, BIN_DIR, PROG, SOURCES )
Ответы
Ответ 1
Ok Третья попытка - это прелесть. Я просто помещаю это в новый ответ, чтобы он был чище. Я разговаривал с моим местным гуру-сёком, и он заявил, что метод установки должен работать, но есть намного более простой способ.
Просто укажите полный путь, по которому вы хотите выполнить исполняемый файл (или dll). Итак:
prj2_env.Program(target = os.path.join(BIN_DIR,PROG), source = SOURCES )
Если вы не хотите делать это во всех местах, вы можете сделать глобальную функцию:
def PrefixProgram(env, trgt, srcs):
env.Program(target = os.path.join(env.["MY_OUTPUT_DIR"], trgt), source = srcs)
Затем в вашем SConscript что-то вроде:
import ('PrefixProgram')
# stuff ...
PrefixProgram(prj2_env, PROG, SOURCES)
Обратите внимание, что вы можете добавить свой собственный атрибут в среду, где находится
env["MY_OUTPUT_DIR"]
. Я написал это с манжетой, поэтому ожидайте некоторые незначительные ошибки синтаксиса, а что нет. Очевидно, вы можете применить тот же трюк для общих и статических библиотек.
В интересах полного раскрытия я предложил моему местному гуру-скаутам возможность ответить на это сам, но он испугался, что он станет зависимым от сайта и отклонится.:)
Ответ 2
ВариантDir - это способ сделать это. Как ваш Sconstruct вызывает ваши файлы Sconscript? Также прочитайте этот раздел документации: http://www.scons.org/doc/1.1.0/HTML/scons-user/c3271.html (предположим, что у вас есть).
Чем больше я думаю об этом, тем больше я думаю, что вы хотите использовать комбинацию По умолчанию и Установить
В вашем вызове SConscripts
env.Install("../bin", <your target exe or dll>)
то в вашем вызове Sconstruct
env.Alias('install', "../bin")
Default('install')
Это должно сделать трюк, и я думаю, что ссылки дают понять, как все это работает.