[linux] 다른 디렉토리에 소스 파일이있는 Makefile

디렉토리 구조가 다음과 같은 프로젝트가 있습니다.

                         $projectroot
                              |
              +---------------+----------------+
              |               |                |
            part1/          part2/           part3/
              |               |                |
       +------+-----+     +---+----+       +---+-----+
       |      |     |     |        |       |         |
     data/   src/  inc/  src/     inc/   src/       inc/

part / src에 있거나 또는 실제로 c / c ++ 소스 파일에서 컴파일 / 링크 할 수있는 makefile을 어떻게 작성해야합니까? / src?

-I $ projectroot / part1 / src -I $ projectroot / part1 / inc -I $ projectroot / part2 / src와 같은 작업을 수행 할 수 있습니까?

그것이 효과가 있다면 더 쉬운 방법이 있습니까? 해당하는 각 부분에 makefile이있는 프로젝트를 보았습니까? 폴더. [이 포스트에서 나는 bash 구문에서와 같이 물음표를 사용했다]



답변

전통적인 방법은이 것입니다 Makefile하위 디렉토리 (각각 part1, part2당신은 독립적으로 구축 할 수 등). 또한 Makefile프로젝트의 루트 디렉토리에 모든 것을 빌드하십시오. “루트” Makefile는 다음과 같습니다.

all:
    +$(MAKE) -C part1
    +$(MAKE) -C part2
    +$(MAKE) -C part3

make 대상의 각 행은 자체 쉘에서 실행되므로 디렉토리 트리 또는 다른 디렉토리로의 순회에 대해 걱정할 필요가 없습니다.

GNU make 매뉴얼 섹션 5.7을 살펴 보는 것이 좋습니다 . 매우 도움이됩니다.


답변

한 서브 디렉토리에 다른 서브 디렉토리의 코드에 종속 된 코드가있는 경우 최상위 레벨의 단일 makefile을 사용하는 것이 좋습니다.

재귀가 유해한 것으로 간주 참조 전체 근거에 대한,하지만 기본적으로는 make가 그것을 다시 작성 여부 파일 요구 사항을 결정하는 데 필요한 모든 정보를 갖고 싶어, 그리고 당신 만의 대략 세 번째를 말한다면 것을 필요가 없습니다 당신의 프로젝트.

위의 링크에 접근 할 수없는 것 같습니다. 동일한 문서를 여기에서 찾을 수 있습니다 :


답변

VPATH 옵션이 유용 할 수 있는데, 이는 소스 코드를 찾을 디렉토리를 지정합니다. 그래도 각 포함 경로에 대해 -I 옵션이 필요합니다. 예를 들면 :

CXXFLAGS=-Ipart1/inc -Ipart2/inc -Ipart3/inc
VPATH=part1/src:part2/src:part3/src

OutputExecutable: part1api.o part2api.o part3api.o

그러면 VPATH 지정 디렉토리에서 일치하는 partXapi.cpp 파일을 자동으로 찾아서 컴파일합니다. 그러나 이것은 src 디렉토리가 서브 디렉토리로 분리 될 때 더 유용합니다. 다른 사람들이 말했듯이, 특히 각 부분이 독립적 일 수 있다면 각 부분에 대한 makefile을 사용하는 것이 좋습니다.


답변

다른 디렉토리에서 필요한 cpp 파일을 컴파일하기 위해 루트 Makefile에 규칙을 추가 할 수 있습니다. 아래의 Makefile 예제는 원하는 곳으로가는 좋은 출발점이되어야합니다.

CC = g ++
목표 = cppTest
OTHERDIR = .. / .. / someotherpath / in / project / src

소스 = cppTest.cpp
소스 = $ (OTHERDIR) /file.cpp

## 최종 소스 정의
INCLUDE = -I./ $ (AN_INCLUDE_DIR)
INCLUDE = -I. $ (OTHERDIR) /../ inc
## 더 포함

VPATH = $ (OTHERDIR)
OBJ = $ (가입 $ (addsuffix ../obj/, $ (dir $ (SOURCE))), $ (notdir $ (SOURCE : .cpp = .o))

## 의존 목적지를 src 디렉토리에 대해 ../.dep로 수정
DEPENDS = $ (가입 $ (addsuffix ../.dep/, $ (dir $ (SOURCE))), $ (notdir $ (SOURCE : .cpp = .d)))

## 기본 규칙 실행
모두 : $ (TARGET)
        @진실

## 깨끗한 규칙
깨끗한:
        @ -rm -f $ (대상) $ (OBJ) $ (DEPENDS)


## 실제 목표를 만들기위한 규칙
$ (대상) : $ (OBJ)
        @echo "============="
        @echo "대상 연결 $ @"
        @echo "============="
        @ $ (CC) $ (CFLAGS) -o $ @ $ ^ $ (LIBS)
        @echo-링크 완료-

## 일반 컴파일 규칙
% .o : % .cpp
        @mkdir -p $ (디렉토리 $ @)
        @echo "============="
        @echo "$ <"컴파일
        @ $ (CC) $ (CFLAGS) -c $ <-o $ @


## cpp 파일의 객체 파일 규칙
## 각 파일의 오브젝트 파일은 obj 디렉토리에 있습니다
## 실제 소스 디렉토리에서 한 단계 위
../obj/%.o : % .cpp
        @mkdir -p $ (디렉토리 $ @)
        @echo "============="
        @echo "$ <"컴파일
        @ $ (CC) $ (CFLAGS) -c $ <-o $ @

# "other directory"에 대한 규칙 "other"디렉토리마다 하나씩 필요합니다.
$ (OTHERDIR) /../ obj / %. o : % .cpp
        @mkdir -p $ (디렉토리 $ @)
        @echo "============="
        @echo "$ <"컴파일
        @ $ (CC) $ (CFLAGS) -c $ <-o $ @

## 의존성 규칙 만들기
../.dep/%.d : % .cpp
        @mkdir -p $ (디렉토리 $ @)
        @echo "============="
        $ *. o의 @echo Building 의존성 파일
        @ $ (SHELL) -ec '$ (CC) -M $ (CFLAGS) $ <| sed "s ^ $ *. o ^ .. / obj / $ *. o ^"> $ @ '

## "기타"디렉토리에 대한 종속성 규칙
$ (OTHERDIR) /../. dep / %. d : % .cpp
        @mkdir -p $ (디렉토리 $ @)
        @echo "============="
        $ *. o의 @echo Building 의존성 파일
        @ $ (SHELL) -ec '$ (CC) -M $ (CFLAGS) $ <| sed "s ^ $ *. o ^ $ (OTHERDIR) /../ obj / $ *. o ^"> $ @ '

## 의존성 파일 포함
-포함 $ (DEPENDS)


답변

소스가 많은 폴더에 분산되어 있고 개별 Makefile을 갖는 것이 합리적이라면 이전에 제안한 것처럼 재귀 적 make가 좋은 접근 방법이지만 소규모 프로젝트의 경우 Makefile의 모든 소스 파일을 상대 경로와 함께 나열하는 것이 더 쉽습니다. 받는 사람 메이크 같은 :

# common sources
COMMON_SRC := ./main.cpp \
              ../src1/somefile.cpp \
              ../src1/somefile2.cpp \
              ../src2/somefile3.cpp \

그런 다음 VPATH이 방법 을 설정할 수 있습니다 :

VPATH := ../src1:../src2

그런 다음 객체를 만듭니다.

COMMON_OBJS := $(patsubst %.cpp, $(ObjDir)/%$(ARCH)$(DEBUG).o, $(notdir $(COMMON_SRC)))

이제 규칙은 간단합니다.

# the "common" object files
$(ObjDir)/%$(ARCH)$(DEBUG).o : %.cpp Makefile
    @echo creating $@ ...
    $(CXX) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<

그리고 출력을 만드는 것이 훨씬 쉽습니다.

# This will make the cbsdk shared library
$(BinDir)/$(OUTPUTBIN): $(COMMON_OBJS)
    @echo building output ...
    $(CXX) -o $(BinDir)/$(OUTPUTBIN) $(COMMON_OBJS) $(LFLAGS)

다음을 통해 VPATH세대를 자동화 할 수도 있습니다 .

VPATH := $(dir $(COMMON_SRC))

또는 sort중복 을 제거 한다는 사실을 사용하십시오 (중요하지는 않지만).

VPATH := $(sort  $(dir $(COMMON_SRC)))


답변

오늘날 도구와 비교할 때 배우고 유지 관리하고 확장하기가 어렵 기 때문에 Make (재귀 적이거나 그렇지 않은)를 사용하는 것이 일반적으로 피하고 싶을 것이라고 지적하는 것이 좋습니다.

훌륭한 도구이지만 2010 년에는 직접 사용하지 않는 것으로 간주됩니다.

물론, 당신은 레거시 프로젝트 등과 같은 특별한 환경에서 일하고 있지 않다면.

IDE, CMake 또는 하드 코어 된 경우 Autotools를 사용하십시오 .

(공포로 인해 편집 됨, ty Honza 지적)


답변

RC의 게시물은 매우 유용했습니다. 나는 $ (dir $ @) 함수를 사용하는 것에 대해 생각하지 않았지만, 내가해야 할 일을 정확하게 수행했습니다.

parentDir에는 dirA, dirB, dirC와 같은 소스 파일이있는 디렉토리가 많이 있습니다. 다양한 파일은 다른 디렉토리의 객체 파일에 의존하므로 한 디렉토리에서 하나의 파일을 만들고 해당 종속성과 관련된 makefile을 호출하여 해당 파일을 만들 수 있기를 원했습니다.

본질적으로, 나는 많은 다른 것들 중에서도 RC와 비슷한 일반적인 규칙을 가진 하나의 Makefile을 parentDir에 만들었습니다.

%.o : %.cpp
        @mkdir -p $(dir $@)
        @echo "============="
        @echo "Compiling $<"
        @$(CC) $(CFLAGS) -c $< -o $@

각 서브 디렉토리에는이 일반 규칙을 상속하기 위해이 상위 레벨 makefile이 포함되었습니다. 각 하위 디렉토리의 Makefile에서 각 파일에 대한 사용자 지정 규칙을 작성하여 각 개별 파일이 의존하는 모든 것을 추적 할 수있었습니다.

파일을 만들어야 할 때마다 (필수적으로)이 규칙을 사용하여 모든 / 모든 종속성을 재귀 적으로 만들었습니다. 완전한!

참고 :이 작업을 훨씬 직관적으로 수행하는 것처럼 보이는 “makepp”라는 유틸리티가 있지만 다른 도구에 의존하지 않고 이식성을 위해이 방법으로 선택했습니다.

도움이 되었기를 바랍니다!