2012-12-17 2 views
2

코드베이스를 리팩토링하고 서로 다른 구성 요소 간의 직접적인 종속성을 제한하려고합니다. 소스 트리는 src/a, src/b 및 src/c와 같은 몇 개의 최상위 디렉토리를 가지고 있습니다.makefile에서 C++의 종속성 제한을 적용 할 수 있습니까?

  • 파일 A는 파일 A를하지만
  • 파일 C C에 따라 달라질 수 있습니다 B에서 B 또는 C
  • 파일에있는 파일의 의존 할 수에서 :

    우리는 restirctions의 집합을 적용 할 직접 파일에 의존 할 수 있지만 a는 없습니다.

첫 번째 시행은 간단합니다. 나는이 같은 묵시적 ​​규칙이 : 헤더가 발견되지 않는 등의 시도에서 파일이 B 또는 C에서 헤더 파일을 포함 할 경우

build/a/%.o : src/a/%.cpp 
    $(CXX) -I src/a $(OTHER_FLAGS) -o [email protected] $< 

를 빌드가 실패합니다.

두 번째 규칙은 src/a와 src/b를 포함 디렉토리로 지정하는 비슷한 규칙을 가지고 있습니다. 문제는 건물 c와 함께 발생합니다. 다음이 허용됩니다.

src/c/C.cpp 
#include "b.h" 
void C() { ... } 

src/b/b.h 
#include "a.h" 
class B { ... }; 

src/a/a.h 
class A { ... }; 

여기서, C에서 파일 차례로 (또는 허용) (A)로부터 파일을 포함하는 (수) (B)로부터의 파일을 포함한다. 우리는이 같은 코드를 방지하려면 : 허용 된 경우 컴파일

src/c/C_bad.cpp 
// Direct inclusion of a 
#include "a.h" 

src/c/c_bad.h 
// Direct inclusion of a 
#include "a.h" 

를 들어, 컴파일 a를 -Isrc/A를 포함해야 SRC/C 파일을 구축하기위한 명령하지만, 그 두 번째의 경우는 컴파일 할 수 있습니다.

필자는 내 문제에 대한 대답이 컴파일러에서 생성 된 종속성을 확인하고 잠재적으로 불법적 인 종속성을 찾은 다음 소스 파일을보고 이것이 직접적인 종속성인지 확인하는 스크립트를 작성한 것으로 의심됩니다. 컴파일러 및/또는 makefile 구조를 결합하는 합리적인 방법이 있습니까?

우리는 GNU Make 3.81과 g ++ 4.5.3을 사용하고 있지만 가능한 경우 이식성이 좋고 싶습니다.

우리는 그것, 그것은 규칙을 준수하는 노력이 필요없는 하나의 규칙을 위반하는 노력이 필요 뭔가를 찾고있다

업데이트. (과거의 경험은 후자가 작동하지 않을 것으로 나타났습니다.) 다른 대답에는 좋은 아이디어가 있지만, 스크립트를 작성하는 것을 받아들입니다. 스크립트를 작성하는 것이 가장 효과적입니다. 약.

답장을 보내 주셔서 감사합니다.

답변

0

기존 코드 기반에 적용한다는 점을 감안할 때 "유효성 검사 스크립트"접근 방식을 선택합니다.

빌드가 실패 할 때마다 빌드 프로세스를 수정하고 종속성을 한 번에 하나씩 분리하는 대신 불만 사항이 아닌 파일 목록이 표시됩니다. 그런 다음 "큰 그림"을 염두에두고 코드베이스를 리팩터링 할 수 있으며 변경 사항은 이전과 동일한 Makefile을 사용하여 작성되므로 테스트 및 디버깅이 간단 해집니다.

일단 리팩토링되면 분석 스크립트는 향후 업데이트를 확인하기 위해 컴플라이언스 검사기로 계속 사용될 수 있습니다.

이러한 분석의 가능한 시작점은 makedepend 또는 cpp -MM입니다. 예를 들어, 당신이 질문에 열거 한 CPP/h의 파일을 사용하여 :

 
[[email protected]]$ find . 
. 
./b 
./b/b.h 
./a 
./a/a.h 
./c 
./c/C_bad.cpp 
./c/C.cpp 
./c/c_bad.h 

[[email protected]]$ cpp -MM -Ia -Ib -Ic */*.cpp 
C_bad.o: c/C_bad.cpp a/a.h 
C.o: c/C.cpp b/b.h a/a.h 

[[email protected]]$ # This also works for header files 
[[email protected]]$ cpp -Ia -Ib -Ic -MM c/c_bad.h 
c_bad.o: c/c_bad.h a/a.h 

각각의 CPP 파일의 의존성 및 플래그 비있는 자들을 결정하기 위해 그 출력을 구문 분석하는 데 합리적으로 솔직해야한다 - 준수.

이 방법의 단점은 그 중요한 경우 소스를 검사하고 직접 종속성을 골라하는 추가 단계를 포함 할 필요가 있습니다 그래서, 직접 및 간접 종속성을 구별 할 수 없다는 것입니다. 내가 (안 세부 디렉토리에서) SRC/B/b.h에서 "a.h을"#include를 할 경우

0

예. 그러나 수동적 인 노력과 규율이 필요합니다.

C를 빌드 할 때 src/b/*. h의 헤더에 의존 할 수 있습니다.

프로젝트 B 내부의 주 디렉터리에있는 모든 헤더 파일은 독립적이어야하며 다른 프로젝트에 종속되지 않아야합니다. B src/b/detail/*. h 내부에 서브 디렉토리가 필요합니다. 여기서 헤더 파일은 src/a/*. h와 src/b/*. h를 포함 할 수 있지만 이것은 개인 구현 세부 사항이며 b 프로젝트의 소스 파일에서만 사용할 수 있습니다.

+0

, 빌드가 실패 할 수있다, 또는 우리는 그것을 잡으려고 코드 리뷰에 의존해야? 당신이 또한 SRC/B/세부/b.h에서 C/c.h을 포함 실패 빌드를 수없는 것 같다. 그 맞습니까? –

0

당신은 만들 수 -I 옵션 대상별 : 그것은 휴대용하지 그래서

build/b/%.o: CPPFLAGS += -Isrc/a 
build/c/%.o: CPPFLAGS += -Isrc/b 

이하지만, GNU-메이크업에 따라 다릅니다.

0

가장 쉬운 방법은 포함 경로를 -Isrc으로 변경하는 것입니다. 포함 문은 완전한 상대 경로를 갖습니다.

#include <a/a.h> 

예를 들면 다음과 같습니다. 이렇게하면 코드를 자동으로 확인하는 것이 훨씬 쉬워집니다 (메이크 파일이 아닌 커밋 훅에서). 이러한 규칙에 A와 B를 수 있도록 지금

// src/a/a.h 
#ifndef SRC_A_H 
#define SRC_A_H 
#ifndef ALLOW_A 
#error "you're not allowed to include A headers here" 
#endif 
//... 

// src/b/b.h 
#ifndef SRC_B_H 
#define SRC_B_H 
#ifdef ALLOW_A_INDIRECT 
#define ALLOW_A 
#endif 

#include <a/a.h> 
//... 
#ifdef ALLOW_A_INDIRECT 
#undef ALLOW_A 
#endif 
#endif // include guard 

:


또는, 는 A의 매크로와 B 헤더와 불쾌한 뭔가를 할 수 빌드 완료 :

build/a/%.o: CPPFLAGS += -DALLOW_A 
build/b/%.o: CPPFLAGS += -DALLOW_A 

이이 특히 B의 헤더에 약간의 훈련이 필요하지만, 나는 그것을 함께 기존 앉아 경우 가정을 가드를 포함 C의 B를 통해 전용 액세스 (및 매크로 B의 헤더)

build/c/%.o: CPPFLAGS += -DALLOW_A_INDIRECT 

참고하실 수 있습니다. .. 좋아, 그것은 실제로 아직도 더러운.

관련 문제