2009-10-14 2 views
47

-j에 대해 배웠던 이래로 -j8 blithely를 사용했습니다. 다른 날에 아틀라스 설치를 컴파일 중이었고 make가 실패했습니다. 결국 나는 그것을 순서를 벗어난 것으로 추적했다. 그리고 한번 singlethreaded make로 돌아 가면 잘 돌아갔다. 이것은 나를 긴장하게 만든다. make -j를 사용하여 예상치 못한 일을 피하기 위해 자신의 make 파일을 작성할 때 어떤 조건을 고려해야합니까?GNU make 's -j option

+4

-j4는 당신이의 잘못이 확인 확신되어 있는지 확인합니다

그런 다음 실행 메이크업은과 차이점을 보여줍니다? 올바른 makefile을 작성하는 것은 오류가 발생하기 쉽습니다. –

+1

Meh, autotools에서 생성 된 메이크 파일조차도 버그가 있습니다. -j2 이상으로 GCC 컴파일을 시도하십시오. – LiraNuna

답변

36

make -j는 Makefile에서 지정하는 종속성을 존중할 것이라고 생각합니다. 즉, objA가 objB와 objC에 의존한다고 지정하면 objB와 objC가 완료 될 때까지 make는 objA에서 작업을 시작하지 않습니다.

대부분의 경우 당신의 Makefile은 필요한 작업 순서를 엄격하게 지정하지 않으므로 단일 스레드의 경우에 당신을 위해 일하는 것이 행운입니다.

+10

맞습니다. 나는 약 2 천만 라인의 코드베이스를 다루고 있는데, 대부분 C 언어로되어 있고 C++로되어있다. 이것은 수백 개의 구성 요소로 나뉘며, 그 중 절반은 make를 사용하고 나머지 절반은 잼을 사용합니다. 나는 항상 -j 옵션을 사용하여 병렬 컴파일을 수행한다. 그렇지 않으면 빌드에 몇 시간이 걸릴 것입니다. Jam은 자체 종속성을 생성하므로 항상 종속성을 사용하는 구성 요소가 성공합니다. 그러나 수작업으로 만들어진 메이크 파일을 사용하는 구성 요소는 때로는 부적절한 종속성으로 인해 질식합니다. –

+0

나는 웹에서'-j'가 얼마나 많은 CPU를 컴파일하려고 하는지를 보았다. 나는 내 8 코어 머신에서 테스트를 실행했고'make '는'-j8'까지 ('-j8'와 비슷한 모든 코어에서 100 % 사용)를 포함하여 작동합니다. 각각의 정수가 증가 할 때마다 또 다른 핵심 사용이 대략 * 100 % * 증가 할 것입니다. '-j' 값으로 무엇을 지정할지를 아는 것이 좋은 경험 법칙이라고 할 수 있겠습니까? – Jacksonkr

+0

알고있는 유일한 좋은 규칙은 (n)의 다양한 값을 사용하여 "make clean, make make -jn"을 수행하고 각 빌드가 소요되는 시간을 확인한 다음 완료된 설정으로 이동하는 것입니다 최소한의 시간. 유용한 일반화를 이루기에는 너무 많은 변수 (CPU 속도, RAM 속도, RAM 크기, 하드 드라이브 속도, OS 프로세스 오버 헤드 등)가 있습니다. –

22

간략하게 - 종속성이 정확하고 완전한지 확인하십시오.

단일 스레드 만들기를 사용하는 경우 맹목적으로 대상 간의 암시 적 종속성을 무시할 수 있습니다. 병렬 make를 사용할 때 암시 적 종속성에 의존 할 수 없습니다. 그들은 모두 명시해야합니다. 이것은 아마도 가장 일반적인 함정입니다. 특히 .phony 대상을 종속 항목으로 사용하는 경우.

This 링크는 병렬 작성과 관련된 몇 가지 문제점에 대한 좋은 입문서입니다.

+0

+1 좋은 링크. 나는 이제 make -j도 믿을 수 있고 문제가 발생할 때 문제를 해결할 수있는 것처럼 느낍니다. 읽는 가치가 있습니다. –

7

재귀 적 make를 사용하면 상황이 매우 쉽게 손상 될 수 있습니다. 재귀 적으로 make를하고 있지 않다면, 의존성이 정확하고 완벽하면, 어떤 문제도 일으키지 않아야한다. 재귀 적 make와 관련된 문제에 대한 자세한 설명은 Recursive Make Considered Harmful을 참조하십시오.

8

다음은 병렬 빌드를 사용하기 시작한 때의 문제에 대한 예입니다. 목표를 처음부터 다시 작성하는 데 사용하는 "신선한"대상이 있습니다 ("신선한"빌드). 과거에는 간단하게 "clean"을 표시하고 "build"를 종속 항목으로 지정하여 "신선한"대상을 코딩했습니다. 내가 병렬를 사용하여 시작할 때까지 잘 작동

build: ## builds the default target 
clean: ## removes generated files 
fresh: clean build ## works for -j1 but fails for -j2 

빌드하지만 병렬 빌드와 함께, 그것은 모두 "깨끗한"과 동시에 "구축"할 시도합니다. 그래서 올바른 순서의 작업을 보장하기 위해 다음과 같이 "신선함"의 정의를 변경했습니다.

fresh: 
    $(MAKE) clean 
    $(MAKE) build 

이것은 근본적으로 종속성을 올바르게 지정하는 문제입니다. 단일 스레드 빌드보다 병렬 빌드가 더 엄격하다는 것이 트릭입니다. 내 예제는 주어진 타겟에 대한 의존성 목록이 반드시 실행 순서를 나타내는 것은 아니라는 것을 보여줍니다.

+2

재귀 make, yuk !. build_가 물론 build_ clean 이전에 항상 _please가 깨끗하게 처리한다고 말하는 올바른 방법이 있습니다. – bobbogo

+1

@bobbogo : 빌드하기 전에 항상 깨끗하게하고 싶지는 않습니다. 대부분의 경우 불필요합니다. 필자가 설명한 "신선한"목표는 기본적으로 "make clean"을 실행하는 단순한 스크립트이며 "make build"가 있습니다. 이 시나리오에서는 make를 재귀 적으로 실행하는 데 아무런 해가 없습니다. – nobar

+2

조건부로 보호하는 방법 :'ifeq ($ (MAKECMDGOALS), fresh); 빌드 : 깨끗한; endif' (세미콜론을 개행 문자로 대체)? – eriktous

1

모든 make 파일의 -j 옵션을 테스트하는 자동화 된 테스트를하는 것이 좋습니다. 심지어 최고의 개발자도 make의 -j 옵션에 문제가 있습니다. 가장 일반적인 문제는 가장 간단합니다.

myrule: subrule1 subrule2 
    echo done 

subrule1: 
    echo hello 

subrule2: 
    echo world 

일반적인 make에서는 hello -> world -> done이 표시됩니다. make -j 4를 사용하면 world -> hello -> done을 볼 수 있습니다.

여기서 가장 많이 볼 수있는 것은 출력 디렉토리를 만드는 것입니다.예 :

build: $(DIRS) $(OBJECTS) 
    echo done 

$(DIRS): 
    [email protected] -p [email protected] 

$(OBJECTS): 
    $(CC) ... 
0

효과를 명확하게 나타내지 않으므로 subsetbrew의 답변에 추가 할 것이라고 생각했습니다. 그러나 몇 가지 휴면 명령어를 추가하면됩니다. 글쎄 리눅스에서 작동합니다.


all: toprule1 

toprule1: botrule2 subrule1 subrule2 
    @echo toprule 1 start 
    @sleep 0.01 
    @echo toprule 1 done 

subrule1: botrule1 
    @echo subrule 1 start 
    @sleep 0.08 
    @echo subrule 1 done 

subrule2: botrule1 
    @echo subrule 2 start 
    @sleep 0.05 
    @echo subrule 2 done 

botrule1: 
    @echo botrule 1 start 
    @sleep 0.20 
    @echo "botrule 1 done (good prerequiste in sub)" 

botrule2: 
    @echo "botrule 2 start" 
    @sleep 0.30 
    @echo "botrule 2 done (bad prerequiste in top)" 
관련 문제