红联Linux门户
Linux帮助

make时出现execvp: Argument list too long解决方法

发布时间:2016-10-14 10:45:09来源:linux网站作者:ayu_ag
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中循环出现了如下的东西:
make时出现execvp: Argument list too long解决方法
 
然后搜索在编译系统框架里面搜索一下哪里设置了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)的环境变量和出问题的不同,具体的没有看
打完收工。
 
本文永久更新地址:http://www.linuxdiyf.com/linux/25026.html