make时出现了错误提示:
make: execvp: /bin/sh: Argument list too long
参数列表过长?经过国正同学的不断排查,发现任何一条make里面调用的shell命令都会报这个错误,比如"ls"。
如果前面加上"$(shell)"就不会报参数列表过长了,但是命令执行错误的返回值被搞丢了,执行错误后make不会停止
在网上找到了篇资料:
http://www.in-ulm.de/~mascheck/various/argmax/
里面提到了使用xargs --show-limits 可以查看系统中对于参数长度的限制:
xargs --show-limits
Your environment variables take up 4222 bytes
POSIX upper limit on argument length (this system): 2090882
POSIX smallest allowable upper limit on argument length (all systems): 4096
Maximum length of command we could actually use: 2086660
Size of command buffer we are actually using: 131072
1、目前所有环境变量加起来的长度为4222,注意不是上限
2、所有环境变量+所有命令行参数长度上限为2090822
3、POSIX规定所有环境变量+所有命令行参数长度上限不低于4096
4、所有命令行参数长度上限2086660 = 2090882 - 4222
5、单个环境变量 or 命令行参数长度上限131072
单个环境变量超长的的测试方法:
shuyin.wsy@10-101-175-19:/disk7/shuyin.wsy$ export LONG_ENV="$(seq 1 23697)"
shuyin.wsy@10-101-175-19:/disk7/shuyin.wsy$ ls
-bash: /bin/ls: Argument list too long
shuyin.wsy@10-101-175-19:/disk7/shuyin.wsy$ env
-bash: /usr/bin/env: Argument list too long
shuyin.wsy@10-101-175-19:/disk7/shuyin.wsy$ unset LONG_ENV
shuyin.wsy@10-101-175-19:/disk7/shuyin.wsy$ ls
main.c
单个参数超长的测试方法:
shuyin.wsy@10-101-175-19:/disk7/shuyin.wsy$ ls "$(seq 1 23697)"
-bash: /bin/ls: Argument list too long
"$(seq 1 23696)"的长度为131070,那么"$(seq 1 23697)"刚好超过131072
shuyin.wsy@10-101-175-19:/disk7/shuyin.wsy$ echo "$(seq 1 23696)" | wc -c
131070
下载make的源代码(http://ftp.gnu.org/gnu/make/),搜索execvp,发现只在job.c里面调用了两次,添加打印log的patch:
@@ -1978,6 +1978,19 @@
/* Replace the current process with one running the command in ARGV,
with environment ENVP. This function does not return. */
+void execvp_debug(char **argv)
+{
+ char **p;
+ if (!argv)
+return ;
+ printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n\n\nexecvp_debug: ");
+ for (p=argv; *p; p++)
+ {
+printf("%s ", *p);
+ }
+ printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n\n\n\n");
+}
+
/* EMX: This function returns the pid of the child process. */
# ifdef __EMX__
int
@@ -2075,6 +2088,8 @@
/* Run the program. */
environ = envp;
+ execvp_debug(envp);
+ execvp_debug(argv);
execvp (argv[0], argv);
# endif /* !__EMX__ */
@@ -2139,6 +2154,7 @@
if (pid >= 0)
break;
# else
+execvp_debug(new_argv);
execvp (shell, new_argv);
# endif
if (errno == ENOENT)
./configure && make编译完毕,在工作目录中使用绝对路径调用新编译的make:/disk7/shuyin.wsy/make/make-3.81
看看log,发现PATH中循环出现了如下的东西:
然后搜索在编译系统框架里面搜索一下哪里设置了PATH,发现几个.mk里面有如下的代码:
PATH:= $(XMAKE_BUILD_OUT)/host/bin:$(XMAKE_BUILD_OUT)/host/sbin:$(XMAKE_ROOT)/prebuilts/devtools:$(PATH)
很明显这些mk被include了很多次,导致环境变量PATH的长度超长了,include多次是合理的用法,所以我们需要在添加PATH时进行一下处理,保证每次不添加重复的东西。
所以,我定义了如下的两个make的函数:
define append-path
$(strip \
$(eval LOCAL_PATH_ARRAY:=$(subst :, ,$(PATH))) \
$(eval LOCAL_ADD_PATH_ARRAY:=$(subst :, ,$(strip $(1)))) \
$(eval LOCAL_ADD_PATH_ARRAY:=$(foreach dir,$(LOCAL_ADD_PATH_ARRAY),$(if $(filter $(LOCAL_PATH_ARRAY),$(dir)),,$(dir)))) \
$(subst $(space),:,$(strip $(LOCAL_PATH_ARRAY) $(LOCAL_ADD_PATH_ARRAY))) \
)
endef
define prepend-path
$(strip \
$(eval LOCAL_PATH_ARRAY:=$(subst :, ,$(PATH))) \
$(eval LOCAL_ADD_PATH_ARRAY:=$(subst :, ,$(strip $(1)))) \
$(eval LOCAL_ADD_PATH_ARRAY:=$(foreach dir,$(LOCAL_ADD_PATH_ARRAY),$(if $(filter $(LOCAL_PATH_ARRAY),$(dir)),,$(dir)))) \
$(subst $(space),:,$(strip $(LOCAL_ADD_PATH_ARRAY) $(LOCAL_PATH_ARRAY))) \
)
endef
然后修改mk中添加PATH的代码为:
PATH:= $(call prepend-path, $(XMAKE_BUILD_OUT)/host/bin:$(XMAKE_BUILD_OUT)/host/sbin:$(XMAKE_ROOT)/prebuilts/devtools)
PS:
1、关于int execvp(const char *file, char *const argv[]);
The execlp(), execvp(), and execvpe() functions duplicate the actions
of the shell in searching for an executable file if the specified file‐
name does not contain a slash (/) character. The file is sought in the
colon-separated list of directory pathnames specified in the PATH envi‐
ronment variable. If this variable isn't defined, the path list
defaults to the current directory followed by the list of directories
returned by confstr(_CS_PATH). (This confstr(3) call typically returns
the value "/bin:/usr/bin".)
如果file不是"/"开头的,那么会从环境变量里面搜索file,然后去运行。
程序使用的环境变量可以通过extern char **environ;找到。
2、为什么用$(shell)就没有Argument list too long了呢
猜测是$(shell)的环境变量和出问题的不同,具体的没有看
打完收工。