makefile의 매개변수 목록이 너무 깁니다. 오류

makefile의 매개변수 목록이 너무 깁니다. 오류

내가 가지고있는 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 Make1990년대 초에 최적화가 도입되었습니다.

  • 명령줄에 셸 메타 문자가 포함되어 있지 않으면 make명령줄 자체에 태그를 지정하고 다음과 같이 명령을 호출합니다. execv()셸 호출의 오버헤드를 방지합니다.

나중에 이 최적화가 채택 gmake되었습니다 smake.

smake2012년에는 또 다른 최적화가 도입되었습니다.

  • 셸 명령이 echoa로 끝나는 간단한 명령으로 도입되고 ; 다음 명령줄에 셸 메타 문자가 포함되어 있지 않으면 echovia 뒤의 명령이 인라인되어 실행되어smake 최신 빌드 시스템에서 명령을 억제하기 위해 자주 사용하는 오버헤드를 줄입니다. , 대신 출력을 더 쉽게 이해할 수 있도록 단순화된 호출을 사용합니다(예를 들어 1993년 2월에 도입된 Schily Makefile 시스템 참조).;execv()@makeechomake

명령줄에 셸 메타 문자가 포함되어 있으므로 이러한 규칙은 명령줄 make에 적용되지 않습니다. make따라서 전체 명령은 다음을 통해 호출됩니다.

sh -ce command

여기서 commandmakefile로 인해 발생한 전체 크기를 포함하는 문자열입니다.

이제 Linux 커널은 UNIX나 POSIX와 호환되지 않으며 UNIX에는 존재하지 않았던 추가 제한 사항을 적용하는 것으로 보입니다. 이 추가 제한은 단일 문자열의 최대 길이를 기반으로 하는 것으로 보입니다.

이것이 사실이라면 Linux가 make.

Linux 커널 담당자에게 버그 보고서를 제출하는 것을 고려해 보셨나요?

답변3

이 경우, 귀하의 질문은 왜 이 일을 하고 있습니까? 프로그램 출력이나 glob일 수 있는 모든 파일을 포함하는 일종의 .ignore 파일을 생성하려는 것 같습니다. 전자의 경우 tr중간 변수를 거치지 않고 프로그램 출력을 직접(꼭 필요한 경우) 파이프한 다음 파일로 파이프하는 것이 좋습니다 . glob을 사용한다면 매우 간단한 것을 사용할 수 있습니다.for반지:

for file in *
do
    echo "$file" >> out.txt
done

(필요하다면 Makefile에서 이스케이프하세요.)

일반적으로 말하면:

  • 대규모 데이터 청크의 경우 변수 대신 파이프와 리디렉션을 사용하세요. 이는 실제로 매우 빠릅니다(파이프라인의 각 프로그램이 입력을 처리할 수 있는 만큼 빠르게 입력을 처리하기 때문입니다).
  • 사용xargs정말 필요할 때.
  • 피하다쓸모없는 echos와 cats.

답변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 플랫폼 바이트.

관련 정보