내가 가지고있는 makefile에서
@echo "$(IGNORE_DIRS) $(CLEAN_FILES) $(CLEAN_DIRS) $(REALCLEAN_FILES)" | tr ' ' '\n' >> $@
문제는 그것이 $(CLEAN_FILES)
크기 때문에 make를 실행하면 다음과 같은 결과가 나온다는 것입니다.
make: execvp: /bin/sh: Argument list too long
저는 Xubuntu 18.10을 사용하고 있습니다.
편집: 더 많은 배경 정보를 제공해야 합니다. 제가 작업하고 있는 것은 파일을 자동으로 생성하는 make 규칙(GNU make를 사용하고 있습니다)입니다 .hgignore
. 전체 make 규칙은 다음과 같습니다.
.hgignore : .hgignore_extra
@echo "Making $@"
@rm -f $@
@echo "# Automatically generated by Make. Edit .hgignore_extra instead." > $@
@tail -n +2 $< >> $@
@echo "" >> $@
@echo "# The following files come from the Makefile." >> $@
@echo "syntax: glob" >> $@
@echo "$(IGNORE_DIRS) $(CLEAN_FILES) $(CLEAN_DIRS) $(REALCLEAN_FILES)" | tr ' ' '\n' >> $@
@chmod a-w $@
.PHONY : .hgignore
편집 2: @mosvy의 제안에 따라 나도 시도해 보았습니다.
.hgignore : .hgignore_extra
@echo "Making $@"
@rm -f $@
@echo "# Automatically generated by Make. Edit .hgignore_extra instead." > $@
@tail -n +2 $< >> $@
@echo "" >> $@
@echo "# The following files come from the Makefile." >> $@
@echo "syntax: glob" >> $@
$(file >$@) $(foreach V,$(IGNORE_DIRS) $(CLEAN_FILES) $(CLEAN_DIRS) $(REALCLEAN_FILES),$(file >>$@,$V))
@true
@chmod a-w $@
.PHONY : .hgignore
이 명령을 실행한 후에는 make .hgignore
더 이상 "인수 목록이 너무 김" 오류가 발생하지 않지만 결과 .hgignore 파일에는 syntax: glob
해당 행 앞의 출력만 포함되고 그 이후에는 아무것도 포함되지 않습니다.
답변1
@schily가 이미 설명했듯이 이것은 쉘 문제가 아니며 xargs
인용, 더 많은 에코로 분할 ;
등을 사용하여 해결할 수 없습니다. make 작업의 모든 텍스트는 단일 인수로 전달되며 execve(2)
운영 체제에서 허용하는 최대 크기보다 길 수 없습니다.
GNU make(Linux에서는 기본값)를 사용하는 경우 다음을 사용할 수 있습니다.file
그리고foreach
기능:
TEST = $(shell yes foobar | sed 200000q)
/tmp/junk:
$(file >$@) $(foreach V,$(TEST),$(file >>$@,$V))
@true
.PHONY: /tmp/junk
그러면 $(TEST)
개행 문자로 구분된 모든 단어가 이름이 지정된 파일에 인쇄 됩니다 $@
. make 의 유사한 예를 기반으로 합니다.수동.
여러분의 Makefile은 멋진 GNU 기능이 필요하지 않고 좀 더 관리하기 쉬운 것으로 재설계될 수 있지만 게시한 코드 조각에서는 어떻게 하는지 알기 어렵습니다.
고쳐 쓰다:
질문의 정확한 부분에 대해 다음을 수행할 수 있습니다.
.hgignore : .hgignore_extra
$(info Making $@)
$(file >[email protected])
$(file >>[email protected],# Automatically generated by Make. Edit .hgignore_extra instead.)
$(shell tail -n 2 $< >>[email protected])
$(file >>[email protected],)
$(file >>[email protected],# The following files come from the Makefile.)
$(file >>[email protected],syntax: glob)
$(foreach L, $(IGNORE_DIRS) $(CLEAN_FILES) $(CLEAN_DIRS) $(REALCLEAN_FILES), $(file >>[email protected],$L))
@mv -f [email protected] $@
@chmod a-w $@
.PHONY : .hgignore
.hgignore.new
먼저 작성 하고 모든 것이 잘되면 전송 .hgignore.new
되도록 약간 변경했습니다 .hgignore
. 들여쓰기 공간을 다시 탭으로 변경해야 합니다.무음인터페이스가 공백을 파괴하고 있습니다.
답변2
존재하다유닉스 시스템다음 규칙이 적용됩니다.
다음 데이터는 프로세스의 초기 스택을 구성합니다.
- 모든 환경 문자열의 strlen() 합계 + 각 문자열의 마지막 null 문자
- strlen() 모든 인수 문자열의 합계 + 각 문자열의 마지막 null 문자
- 환경 배열: n+1 환경 문자열 * 문자 크기 *
- argv 배열: n+1 매개변수 문자열 * 문자 크기 *
- 추가 숫자
이 모든 데이터를 초과해서는 안 됩니다 ARG_MAX
.
ARG_MAX
과거 UNIX에서는10240또는20480바이트.
SunOS-4.0(1987년 12월 출시)은 이 제한을 다음으로 높였습니다.1MB
Solaris-7.0(1997년 출시)은 64비트 지원을 도입했으며, 64비트 시스템의 실제 사소한 제한(더 큰 env
합계 argv
배열 로 인한 char *
)을 피하기 위해 ARG_MAX
다음으로 승격되었습니다.2MB64비트 프로그램의 경우.
참고: 최신 POSIX 호환 운영 체제에는 getconf
프로그램 지원 및 getconf ARG_MAX
실제 값 인쇄가 포함됩니다. 64비트 Linux에서는 다음을 반환합니다.2MB따라서 Linux에서의 첫 번째 보기는~인 것 같다SunOS 향상 기능 제공...
이제 보자 make
:
프로그램 make
은 다음을 통해 명령을 호출합니다 Makefiles
.
sh -ce command
command
은 어디에 있나요?단일 매개변수그건확장하다작업 줄에 표시되는 문자열입니다 Makefile
.
SunPro Make
1990년대 초에 최적화가 도입되었습니다.
- 명령줄에 셸 메타 문자가 포함되어 있지 않으면
make
명령줄 자체에 태그를 지정하고 다음과 같이 명령을 호출합니다.execv()
셸 호출의 오버헤드를 방지합니다.
나중에 이 최적화가 채택 gmake
되었습니다 smake
.
smake
2012년에는 또 다른 최적화가 도입되었습니다.
- 셸 명령이
echo
a로 끝나는 간단한 명령으로 도입되고;
다음 명령줄에 셸 메타 문자가 포함되어 있지 않으면echo
via 뒤의 명령이 인라인되어 실행되어smake
최신 빌드 시스템에서 명령을 억제하기 위해 자주 사용하는 오버헤드를 줄입니다. , 대신 출력을 더 쉽게 이해할 수 있도록 단순화된 호출을 사용합니다(예를 들어 1993년 2월에 도입된 Schily Makefile 시스템 참조).;
execv()
@
make
echo
make
명령줄에 셸 메타 문자가 포함되어 있으므로 이러한 규칙은 명령줄 make
에 적용되지 않습니다. make
따라서 전체 명령은 다음을 통해 호출됩니다.
sh -ce command
여기서 command
makefile로 인해 발생한 전체 크기를 포함하는 문자열입니다.
이제 Linux 커널은 UNIX나 POSIX와 호환되지 않으며 UNIX에는 존재하지 않았던 추가 제한 사항을 적용하는 것으로 보입니다. 이 추가 제한은 단일 문자열의 최대 길이를 기반으로 하는 것으로 보입니다.
이것이 사실이라면 Linux가 make
.
Linux 커널 담당자에게 버그 보고서를 제출하는 것을 고려해 보셨나요?
답변3
이 경우, 귀하의 질문은 왜 이 일을 하고 있습니까? 프로그램 출력이나 glob일 수 있는 모든 파일을 포함하는 일종의 .ignore 파일을 생성하려는 것 같습니다. 전자의 경우 tr
중간 변수를 거치지 않고 프로그램 출력을 직접(꼭 필요한 경우) 파이프한 다음 파일로 파이프하는 것이 좋습니다 . glob을 사용한다면 매우 간단한 것을 사용할 수 있습니다.for
반지:
for file in *
do
echo "$file" >> out.txt
done
(필요하다면 Makefile에서 이스케이프하세요.)
일반적으로 말하면:
- 대규모 데이터 청크의 경우 변수 대신 파이프와 리디렉션을 사용하세요. 이는 실제로 매우 빠릅니다(파이프라인의 각 프로그램이 입력을 처리할 수 있는 만큼 빠르게 입력을 처리하기 때문입니다).
- 사용
xargs
정말 필요할 때. - 피하다쓸모없는
echo
s와cat
s.
답변4
바라보다이 답변, 특히 이 문장은 다음과 같습니다.
인수 길이는 MAX_ARG_STRLEN(131072)을 초과할 수 없습니다. "sh -c '긴 인수로 빌드'"와 같은 긴 호출을 생성하는 경우 이는 관련성이 있을 수 있습니다.
반면에 전달할 매개변수의 총 개수에 대한 제한은 상당히 높으므로 최종 결과는 echo
동일하므로 별도의 매개변수로 전달하면 되지 않을까요?
이것은 "
원래 명령에서 s를 제거합니다.
@echo $(IGNORE_DIRS) $(CLEAN_FILES) $(CLEAN_DIRS) $(REALCLEAN_FILES) | tr ' ' '\n' >> $@
이는 매개변수 수(상당히 높음)와 각 매개변수의 길이(각 매개변수가 이제 매우 짧기 때문에 더 이상 문제가 되지 않음) 제한 내에서 매개변수를 유지하는 데 충분하기를 바랍니다.
고쳐 쓰다:따옴표를 제거한다고 해서 실제로 문제가 완전히 해결되는 것은 아닙니다. make
셸에서 각 명령을 실행할 때 sh -c '...'
전체 명령에 해당하는 항목이 단일 인수가 되므로 여전히 단일 인수의 길이 제한인 131,072에 묶여 있기 때문입니다. Linux의 x86 플랫폼 바이트.