2012-07-20 69 views
2

我有一個基於SCons的分層構建系統。我有一個根SConstruct,它調用構建共享庫的SConscript,然後構建一個不同的SConscript,構建一個依賴共享庫的可執行文件。SCons庫和子庫

因此,這裏是我的問題:我在Linux上共享庫的理解是,當你想要做的最後ld鏈接的可執行文件將使用共享庫,共享庫必須包含在可執行文件的ld命令行作爲參考源(除非它位於標準位置,在這種情況下-l選項可以工作)。

所以這裏的東西就像我SCons的文件看起來是這樣的:

=== ROOTDIR/SConstruct

env=DefaultEnvironment() 
shared_lib = SConscript('foolib/SConscript') 
env.Append(LIBS=[shared_lib]) 
executable = SConscript('barexec/SConscript') 

=== ROOTDIR/foolib/SConscript

env=DefaultEnvironment() 
env.Append(CPPPATH=Glob('inc')) 
penv = env.Clone() 
penv.Append(CPPPATH=Glob('internal/inc')) 
lib = penv.SharedLibrary('foo', source=['foo.c', 'morefoo.c'] 
Return("lib") 

=== rootdir/barexec/SConscript

env=DefaultEnvironment() 
exe = env.Program('bar', source=['main.c', 'bar.c', 'rod.c']) 
Return("exe") 

所以這裏的結是這一行:

env.Append(LIBS=[shared_lib]) 

這將產生庫添加到了需要它們的任何其他庫的命令行的好方法,但因爲SCons的是做一個兩通運行通過SConscripts(第一生成它的依賴關係樹,然後做的工作),rootdir/foolib/libfoo.so風了所有產品的命令行上,即使libfoo.so本身:

gcc -g -Wall -Werror -o libfoo.so foo.o morefoo.o libfoo.so 

那麼這是怎麼最好地使用SCons做了什麼?現在我已經使出了這個技巧:

=== ROOTDIR/SConstruct

env=DefaultEnvironment() 
shared_lib = SConscript('foolib/SConscript') 
env['shared_lib'] = shared_lib 
executable = SConscript('barexec/SConscript') 

...

=== ROOTDIR/barexec/SConscript

env=DefaultEnvironment() 
exe = env.Program('bar', source=['main.c', 'bar.c', 'rod.c'] + env['shared_lib']) 
Return("exe") 

是還有更多的SCons-y方式來做到這一點?

回答

3

您應該允許通過構建找到共享庫。

SCons文檔中查找LIBPATHRPATH變量;這些是設置搜索路徑的「Scons-y」方法,以便任何生成的-l選項都能正確查找庫。

上面已經提到過,這裏是你基於SCons的設置(如果沒有的話,你可能需要手動去做)應該請參閱gcc

-l選項始終會查找共享庫,前提是您還爲編譯器提供了庫的位置。有兩次需要:編譯時(-L選項)和運行時(-rpath生成鏈接器選項)。

LIBPATH SCons安裝應該爲編譯時搜索路徑生成類似-L/some/directory/path的內容。

RPATH SCons設置應該生成一個鏈接器選項嵌入一個搜索路徑;例如-Wl,-rpath -Wl,\$ORIGIN/../lib將嵌入搜索路徑,以搜索與可執行文件相關的搜索路徑,以便放置在bin中的可執行文件在安裝的並行lib目錄中進行搜索。

+0

這聽起來像個好主意,但是這不會顛覆SCons的依賴檢查嗎?如果我將LIBS = foo添加到條形圖程序環境中,那麼SCons不一定知道gcc獲取libfoo.so的位置(可能是我的項目,可能是/ usr/lib或SCons知道的任何東西),並贏得' t檢測libfoo.so和barexec之間的依賴關係。我不得不通過env.Depends()來破解foo和bar之間的依賴關係嗎? – 2012-07-20 15:02:53

+0

@TedMiddleton,您必須告訴SCons可執行程序需要哪些庫(通過LIBS構建環境)以及它們在哪裏(通過LIBPATH構建環境),然後在此基礎上創建依賴關係樹。 SCons確實會知道它們,因爲它具有這些變量,隨後它會傳遞給gcc或任何編譯器。你不需要用env.Depends()函數破解任何依賴關係。試試吧,你會看到:) – Brady 2012-07-22 09:21:35

2

這是更好的方法來組織您的SConsctruct/SConscript文件。通常在分層構建中,您應該與其他子目錄共享env。請注意,我也在barexec目錄中克隆了主env,以便愚人節僅用於鏈接該二進制文件。

=== ROOTDIR/SConstruct

import os 

env=DefaultEnvironment() 

subdirs = [ 
    'foolib', 
    'barexec' 
] 

# The exports attribute allows you to pass variables to the subdir SConscripts 
for dir in subdirs: 
    SConscript(os.path.join(dir, 'SConscript'), exports = ['env']) 

=== ROOTDIR/foolib/SConscript

# inports the env created in the root SConstruct 
# 
# Any changes made to 'env' here will be reflected in 
# the root/SConstruct and in the barexec/SConscript 
# 
Import('env') 

# Adding this 'inc' dir to the include path for all users of this 'env' 
env.Append(CPPPATH=Glob('inc')) 

penv = env.Clone() 
# Adding this include only for targets built with penv 
penv.Append(CPPPATH=Glob('internal/inc')) 
penv.SharedLibrary('foo', source=['foo.c', 'morefoo.c']) 

=== ROOTDIR/barexec/SConscript

Import('env') 

clonedEnv = env.Clone() 

# The foo lib will only be used for targets compiled with the clonedEnv env 
# Notice that specifying '#' in a path means relative to the root SConstruct 
# for each [item] in LIBS, you will get -llib on the compilation line 
# for each [item] in LIBPATH, you will get -Lpath on the compilation line 
clonedEnv.Append(LIBS=['foo'], LIBPATH=['#foolib']) 

clonedEnv.Program('bar', source=['main.c', 'bar.c', 'rod.c']) 
+0

在問這個問題之後,我發現了一些東西,因爲DefaultEnvironment()通過SConscripts和sub-SConscripts訪問全局變量,所以除非你想傳遞一個不同的環境,否則導入()和Export()不是必須的。 – 2012-07-20 15:05:59

+0

此外,請參閱我上面的Kevin Grant有關LIBS = foo的評論 - SCons是否檢測到libfoo.so和barexec之間的構建依賴關係? – 2012-07-20 15:07:27

+0

@TedMiddleton,我在我的構建系統中做了這種env克隆。不同的環境確實與其變量等有關,但是目標(libfoo.so和barexec)仍然以這種方式「檢測」。我不確定,但我認爲目標是全球性的,他們必須爲此工作,而且確實工作:) – Brady 2012-07-22 09:14:26

2

附加貝迪決定我使用靜態/全局變量來存儲目標名稱和路徑。它允許我更多地控制構建。

# site_scons/project.py 
class Project: 
    APP1_NAME = "app1_name" 
    APP2_NAME = "app2_name" 
    MYLIB1_NAME = "mylib1_name" 
    # etc 
    APP_PATH = "#build/$BuildMode/bin" # BuildMode - commonly in my projects debug or release, `#` - root of project dir 
    LIB_PATH = "#build/$BuildMode/lib" 
    @staticmethod 
    def appPath(name) : 
    return os.path.join(APP_PATH, name) 
    @staticmethod 
    def libPath(name) : 
    return os.path.join(LIB_PATH, name) 

定義目標:

from project import Project 
... 
env.SharedLibrary(Project.libPath(Project.MYLIB1_NAME), source=['foo.c', 'morefoo.c']) 

應用:

from project import Project 
... 
env.Append(LIBPATH = [Project.LIB_PATH]) 
env.Append(LIBS = [Project.MYLIB1_NAME]) 
env.Program(Project.appPath(Project.MYAPP1_NAME), source=[...]) 

在我的項目,它工作正常,scons的自動查找依賴庫沒有任何額外的命令。如果我想更改庫的名稱,只需更改我的Project類。