內建 armcc 到 scons
內建 armcc 到 scons 中并不是件容易的事情,如果隻是修改 CC/CXX/AR/LINK 幾個環境變量,scons 會用 Visual C++的參數調用方式,比如-c 成了/c,導緻 armcc 無法識别。
花了半天時間去閱讀 scons 的源碼後,在 SCons/Tool 目錄下發現,每種編譯器都有一個類似插件的 tool,目測沒有發現 armcc 的 tool,自己為 armcc 寫一個 tool,應該可以解決這個問題。
在 ToolsForFools 這篇文章中,了解到可以自己定義 tool,隻要放到項目的 site_scons/site_tools 目錄下即可。
為了支援 armcc,我們在 site_scons/site_tools/armcc 目錄中建立一個 armcc 的 tool,從頭編寫一個 tool 還是比較麻煩的,考慮到 armcc 和 cc 類似,就直接把 SCons/Tool/cc.py 拷貝到 site_scons/site_tools/armcc/__init__.py,然後在此基礎上進行修改。
在下面這行代碼之後
add_common_cc_variables(env)
增加下面的代碼:
armcc = SCons.Tool.find_program_path(env, 'armcc.exe');
armar = SCons.Tool.find_program_path(env, 'armar.exe');
armlink = SCons.Tool.find_program_path(env, 'armlink.exe');
env['CC'] = armcc
env['CXX'] = armcc
env['AR'] = armar
env['LINK'] = armlink
env['CXXCOM'] = '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES'
env['ARFLAGS'] = SCons.Util.CLVar('--create -r')
env['ARCOM'] = '$AR $ARFLAGS $TARGET $SOURCES'
env['OBJSUFFIX'] = '.o'
env['LIBPREFIX'] = 'lib'
env['LIBSUFFIX'] = '.a'
參考 scons 的 Tool 中的代碼,在 SConstruct 檔案中,加入下面的代碼,來啟用我們前面定義的 armcc:
env = DefaultEnvironment();
SCons.Tool.Tool('armcc')(env)
使用 scons 編譯,編譯正常了,但是在 armar 生成.a 檔案時,出現下面的錯誤:
The command line is too long.
這主要是.o 檔案太多所緻,armar 并不像 ar 那樣可以通過@符合去檔案讀取參數,不過 armar 可以先建立一個.a 檔案,然後一個一個的往裡面追加.o 檔案。
從 scons 的源碼發現,指令最終是在 SCons/Platform/win32.py 裡調用的。但這是系統檔案,直接修改它并不明智,我們還是寫一個 tool 來解決這個問題吧。
為了避免從頭去實作,把 SCons/Platform/win32.py 拷貝到 site_scons/site_tools/win4armcc/__init__.py,然後再去修改。
- 先修改下面幾個變量的值為:
env['OBJSUFFIX'] = '.o'
env['LIBPREFIX'] = 'lib'
env['LIBSUFFIX'] = '.a'
- 增加一個 exists 函數
def exists(env):
return True
- 重新實作 spawn 函數。
def exe_ar(sh, cmd, args, env):
armar = args[0]
#args[1] is --create
#args[2] is -r
target = args[3];
objs = args[4:]
for i in range(len(objs)):
ARFLAGS='-r'
if i == 0:
ARFLAGS='--create -r'
all_args= [armar, target, ARFLAGS, objs[i] ]
sargs = ' '.join(all_args).replace('\\', '/');
print(str(i) + ': ' + sargs);
exec_spawn([sh, '/C', sargs], env)
def spawn(sh, escape, cmd, args, env):
if cmd.endswith('armar.exe'):
exe_ar(sh, cmd, args, env);
else:
sargs = ' '.join(args).replace('\\', '/');
return exec_spawn([sh, '/C', sargs], env)
SCons.Tool.Tool('win4armcc')(env)