[patch for SCons script] ARMCC命令行选项过长时的,ARMCC链接错误

51 views
Skip to first unread message

prife

unread,
Nov 18, 2012, 2:12:32 PM11/18/12
to rt-thread-cnusers
这个问题也是个老话题了。

问题描述:相比大家都比较清楚了,就是当rtconfig.py里使用keil(armcc)时
即CROSS_TOOL = 'keil'

如果rtconfig.h中开启过多的组件,那么编译时就可能出现:
armlink -o rtthread-mini2440.axf --device DARMSS9 --strict --info sizes --info t
otals --info unused --info veneers --list rtthread-mini2440.map --ro-base 0x3000
0000 --entry Entry_Point --first Entry_Point --libpath "D:/Keil/ARM/RV31/LIB" --
keep __rtmsym_* --keep __fsym_* --keep __vsym_* 
........
 build\examples\gui\demo_view_notebook.o build\examples\gui\demo_view
_mywidget.o build\examples\gui\demo_view_box.o build\examples\gui\demo_view_edit
.o build\examples\gui\demo_view_bmp.o build\examples\gui\demo_plot.o build\examp
les\gui\mywidget.o
命令行太长。
scons: *** [rtthread-mini2440.axf] Error 1
scons: building terminated because of errors.

这个问题其实并不是CMD命令行的问题,而是出在ARMCC本身,当命令行参数过长时,armlink就处理不了了,针对这种情况,ARMLINK提供一个选项可以读取文件内容作为 扩展的链接选项。参考mdk的 link user guide

2.2.4. 从文件读取命令选项

如果操作系统限制命令度,则可以使用以下编译器选项在文件中提供附加的命令选项:

--via filename

编译器将打开指定文件,并从中读取附加命令选项。


所以解决方案就是借助临时文件,将obj文件选项都放入一个临时文件中即可,所幸的是SCons也提供了这种方式

以下是SCons邮件列表里给出的解决方案
Try using $TEMPFILE.  MSVC uses it for this purpose.  Start by wrapping the LINKCOM with TEMPFILE like ${TEMPFILE('$LINK ...')} and then maybe set $TEMPFILE to TempFileMunge, and check Platform/__init__.py for how TempFileMunge works; you'll need to make it use the --via or whatever your linker needs.  If you come up with something useful, at least post it on the wiki, or make an add-on tool that people can use (e.g. by putting it in site_scons/tools).

这里以bsp/mini2440为例,共需要打两个补丁

1) SConstruct,patch

Index: SConstruct
===================================================================
--- SConstruct (版本 2411)
+++ SConstruct (工作副本)
@@ -18,6 +18,12 @@
  CXX = rtconfig.CXX,
  AR = rtconfig.AR, ARFLAGS = '-rc',
  LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS)
+if rtconfig.PLATFORM == 'armcc':
+    env["TEMPFILE"] = SCons.Platform.TempFileMunge
+    env["LINKCOM"] = "$LINK -o $TARGET $LINKFLAGS ${TEMPFILE('--via $SOURCES')}"
+    env["TEMPFILEPREFIX"] = ' '      # arm tool chain
+
 env.PrependENVPath('PATH', rtconfig.EXEC_PATH)
 
 Export('RTT_ROOT')

2)给 C:\Python27\Lib\site-packages\scons-2.2.0\SCons\Platform\ __init__.py 打补丁

--- __init__.old.py Mon Nov 19 02:59:32 2012
+++ __init__.py Mon Nov 19 02:59:19 2012
@@ -202,7 +202,7 @@
 
         prefix = env.subst('$TEMPFILEPREFIX')
         if not prefix:
-            prefix = '@'
+            prefix = ''
 
         args = list(map(SCons.Subst.quote_spaces, cmd[1:]))
         os.write(fd, " ".join(args) + "\n")

打上这两个补丁以后, 这个世界清静了。。

使用mini2440分支,开启RTGUI,开启LWIP,开启DFS, ELM, 不打补丁就会报参数过长的错误,打上补丁以后,通过!!

效果:
armlink -o rtthread-mini2440.axf --device DARMSS9 --strict --info sizes --info t
otals --info unused --info veneers --list rtthread-mini2440.map --ro-base 0x3000
0000 --entry Entry_Point --first Entry_Point --libpath "D:/Keil/ARM/RV31/LIB" --
keep __rtmsym_* --keep __fsym_* --keep __vsym_* --via c:\users\admini~1\appdata\
local\temp\tmp05gi1v.lnk
Using tempfile c:\users\admini~1\appdata\local\temp\tmpvte9xd.lnk for command li
ne:
--via build\application.o build\startup.o build\board.o build\console.o build\le
d.o build\sdcard.o build\dm9000.o build\touch.o build\key.o build\calibration.o
build\lcd_t35.o build\src\clock.o build\src\device.o build\src\idle.o build\src\
......................
ox.o build\examples\gui\demo_view_edit.o build\examples\gui\demo_view_bmp.o buil
d\examples\gui\demo_plot.o build\examples\gui\mywidget.o
fromelf --bin rtthread-mini2440.axf --output rtthread.bin
fromelf -z rtthread-mini2440.axf

========================================================================

** Object/Image Component Sizes

      Code (inc. data)   RO Data    RW Data    ZI Data      Debug   Object Name

    629776      33616     705644       3784     170348    2727209   rtthread-min
i2440.axf (uncompressed)
    629776      33616     705644       1544     170348    2727209   rtthread-min
i2440.axf (compressed)
    629776      33616     705644       1544          0          0   ROM Totals f
or rtthread-mini2440.axf
scons: done building targets.

F:\Project\svn\rtt\trunk\bsp\mini2440>

=================================================================================

补充说明:
不过这种处理方式其实是一种hack的方式,因为当前SCons对Tempfile的实现机制有bug,之所以要打第二个补丁,是如果不打补丁, 就会出现 --via @c:\users\admini~1\appdata\local\temp\tmp05gi1v.lnk
这里多出一个@符,本来这@符号应该放到临时文件名前面,而不是加到路径前面的,这回导致无法找到临时文件。

PS: 第一个补丁其实也是hack的方式,正确写法应该如下,但是因为bug的存在,反而无法正确编译
 env["LINKCOM"] = "$LINK -o $TARGET $LINKFLAGS --via  ${TEMPFILE(' $SOURCES')}" 


enjoy~~~

--
把有限的时间投入到无限的学习中去

bernard

unread,
Nov 18, 2012, 6:00:05 PM11/18/12
to rt-thread用户组

scons这个补丁应该可以动态打吧

试着修改下env[' TEMPFILEPREFIX']

Grissiom

unread,
Nov 18, 2012, 7:13:37 PM11/18/12
to rt-threa...@googlegroups.com
第二个补丁很可能把 msvc 的工具链 break 掉……

2012/11/19 prife <gop...@gmail.com>



--
Cheers,
Grissiom

bernard

unread,
Nov 18, 2012, 7:16:54 PM11/18/12
to rt-thread用户组

或者我们不加scons的补丁,直接自行生成一个objects 列表文件(而不是临时文件),让armlink去-via这个文件。

prife

unread,
Nov 18, 2012, 9:28:35 PM11/18/12
to rt-threa...@googlegroups.com
这个我试过了,不起作用。 因为前缀字符也会被放在路径最面前。并且空格字符串会被忽略掉,因此我才给SCons脚本打补丁。
--
把有限的时间投入到无限的学习中去

prife

unread,
Feb 24, 2013, 9:21:16 AM2/24/13
to rt-threa...@googlegroups.com
在 2012年11月19日上午8:16,bernard <bernar...@gmail.com>写道:

或者我们不加scons的补丁,直接自行生成一个objects 列表文件(而不是临时文件),让armlink去-via这个文件。

bernard的设想成为现实了。不再需要对scons打补丁了,只需要打如下补丁就可以完美解决armcc编译时,命令行过长的问题。

diff --git a/bsp/stm32f10x/SConstruct b/bsp/stm32f10x/SConstruct
index 920b24d..c81815b 100644
--- a/bsp/stm32f10x/SConstruct
+++ b/bsp/stm32f10x/SConstruct
@@ -13,16 +13,16 @@ from building import *
 TARGET = 'rtthread-stm32.' + rtconfig.TARGET_EXT
 
 env = Environment(tools = ['mingw'],
- AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS,
- CC = rtconfig.CC, CCFLAGS = rtconfig.CFLAGS,
- AR = rtconfig.AR, ARFLAGS = '-rc',
- LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS)
+    AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS,
+    CC = rtconfig.CC, CCFLAGS = rtconfig.CFLAGS,
+    AR = rtconfig.AR, ARFLAGS = '-rc',
+    LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS)
 env.PrependENVPath('PATH', rtconfig.EXEC_PATH)
 
 if rtconfig.PLATFORM == 'iar':
- env.Replace(CCCOM = ['$CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -o $TARGET $SOURCES'])
- env.Replace(ARFLAGS = [''])
- env.Replace(LINKCOM = ['$LINK $SOURCES $LINKFLAGS -o $TARGET --map project.map'])
+    env.Replace(CCCOM = ['$CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -o $TARGET $SOURCES'])
+    env.Replace(ARFLAGS = [''])
+    env.Replace(LINKCOM = ['$LINK $SOURCES $LINKFLAGS -o $TARGET --map project.map'])
 
 Export('RTT_ROOT')
 Export('rtconfig')
@@ -36,6 +36,23 @@ objs = objs + SConscript( GetCurrentDir() + '/Libraries/SConscript', variant_dir
 if GetDepend('RT_USING_RTGUI'):
     objs = objs + SConscript(RTT_ROOT + '/examples/gui/SConscript', variant_dir='build/examples/gui', duplicate=0)
 
+def mdk_create_tmpfile(tmpfile, objs):
+    # cmdline ='--via '
+    cmdline =''
+    tmpfile = file(tmpfile, 'w')
+    for item in objs:
+        # print type(item), os.path.basename(str(item))
+        cmdline += os.path.normpath(str(item))
+        cmdline += ' '
+
+    tmpfile.write(cmdline)
+    tmpfile.close();
+    return
+
+if rtconfig.PLATFORM == 'armcc':
+    mdk_create_tmpfile('tmpcmd.txt', objs)
+    env["LINKCOM"] = "$LINK -o $TARGET $LINKFLAGS --via tmpcmd.txt"
+
 # build program 
 env.Program(TARGET, objs)
 
diff --git a/tools/building.py b/tools/building.py
index a1e63f8..8f48d62 100644
--- a/tools/building.py
+++ b/tools/building.py
@@ -134,13 +134,13 @@ def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components = [
     objs = SConscript('SConscript', variant_dir='build', duplicate=0)
     Repository(Rtt_Root)
     # include kernel
-    objs.append(SConscript(Rtt_Root + '/src/SConscript', variant_dir='build/src', duplicate=0))
+    objs += (SConscript(Rtt_Root + '/src/SConscript', variant_dir='build/src', duplicate=0))
     # include libcpu
     if not has_libcpu:
-        objs.append(SConscript(Rtt_Root + '/libcpu/SConscript', variant_dir='build/libcpu', duplicate=0))
+        objs += (SConscript(Rtt_Root + '/libcpu/SConscript', variant_dir='build/libcpu', duplicate=0))
 
     # include components
-    objs.append(SConscript(Rtt_Root + '/components/SConscript',
+    objs += (SConscript(Rtt_Root + '/components/SConscript',
                            variant_dir='build/components',
                            duplicate=0,
                            exports='remove_components'))


关键还是 红色部分。这个地方是在邮件 app module for simulator里就打过了补丁。
这个代码可以和Grissiom 的新的scons tools集成起来,统一放在tools/目录下。并且可以专门为mdk增加一个选项,比如
scons --long
之类解决命令行编译的问题。



--
把有限的时间投入到无限的学习中去
scons_armcc_toolong.patch

prife

unread,
Feb 28, 2013, 1:47:38 PM2/28/13
to rt-threa...@googlegroups.com
在 2013年2月24日下午10:21,prife <gop...@gmail.com>写道:
在 2012年11月19日上午8:16,bernard <bernar...@gmail.com>写道:

或者我们不加scons的补丁,直接自行生成一个objects 列表文件(而不是临时文件),让armlink去-via这个文件。

bernard的设想成为现实了。不再需要对scons打补丁了,只需要打如下补丁就可以完美解决armcc编译时,命令行过长的问题。

diff --git a/bsp/stm32f10x/SConstruct b/bsp/stm32f10x/SConstruct
index 920b24d..c81815b 100644
--- a/bsp/stm32f10x/SConstruct
+++ b/bsp/stm32f10x/SConstruct
 Export('RTT_ROOT')
 Export('rtconfig')
@@ -36,6 +36,23 @@ objs = objs + SConscript( GetCurrentDir() + '/Libraries/SConscript', variant_dir
 if GetDepend('RT_USING_RTGUI'):
     objs = objs + SConscript(RTT_ROOT + '/examples/gui/SConscript', variant_dir='build/examples/gui', duplicate=0)
 
+def mdk_create_tmpfile(tmpfile, objs):
+    # cmdline ='--via '
+    cmdline =''
+    tmpfile = file(tmpfile, 'w')
+    for item in objs:
+        # print type(item), os.path.basename(str(item))
+        cmdline += os.path.normpath(str(item))
+        cmdline += ' '
+
+    tmpfile.write(cmdline)
+    tmpfile.close();
+    return
+
+if rtconfig.PLATFORM == 'armcc':
+    mdk_create_tmpfile('tmpcmd.txt', objs)
+    env["LINKCOM"] = "$LINK -o $TARGET $LINKFLAGS --via tmpcmd.txt"
+
 # build program 
 env.Program(TARGET, objs)
这个代码可以和Grissiom 的新的scons tools集成起来,统一放在tools/目录下。并且可以专门为mdk增加一个选项,比如
scons --long
之类解决命令行编译的问题。
 
 本来想通在保持现有bsp/rtconfig.py完全不变的基础上,过修改当前的building.py,实现对所有 stm32 bsp完成对 命令行过长问题的修正。
貌似在当前的tools/script框架下是不可能的。。在现有框架的基础上,不可避免要对rtconfig.py修改才行。

--
把有限的时间投入到无限的学习中去
Reply all
Reply to author
Forward
0 new messages