문제

문제

문제

makefile의 하나 이상의 대상에 대한 종속성을 확인하고 싶습니다. 그래서 저는 메이크파일을 구문 분석한 다음 트리와 같은 형식(들여쓰기, ASCII 아트 등)이나 그래프(점, ...)로 종속성을 표시할 수 있는 프로그램을 찾고 있습니다.

비슷한

다른 상황에 대해 이를 수행하는 프로그램이 있습니다:

  • 팩트리또는채무자각 형식의 소프트웨어 패키지에 대한 종속성을 ASCII 형식과 같은 트리 또는 그래프로 표시할 수 있습니다 dot.
  • gcc -M source_file.cC 소스 파일의 종속성을 make 규칙으로 표시합니다.
  • pstree프로세스 트리의 ASCII 표현을 표시합니다.

진전

내가 찾은 웹 검색 중작은 도움. 그게 내가 시도하게 만들었어

make --always-make --silent --dry-run some_target | \
  grep --extended-regexp 'Considering target file|Trying rule prerequisite'

하지만 이것을 멋진 트리/그래프로 표현하려면 Perl이나 Python에서 구문 분석 코드를 좀 더 해킹해야 할 것 같습니다. 그리고 이런 식으로 정말 완전하고 정확한 그래프를 얻을 수 있을지 아직 모르겠습니다.

요구사항

어떤 방식으로든(기본 제공 규칙 없음, 지정된 대상만, 일부 깊이만) 그래프를 제한하는 것이 좋을 것입니다. 그러나 대부분의 경우 저는 "합리적인" 인간의 종속성을 제공할 도구를 찾고 있습니다. -볼 수 있는 형식("유사" 아래의 프로그램과 유사).

질문

  • 이것을 할 수 있는 프로그램이 있나요?
  • 로부터 완전하고 정확한 정보를 얻을 수 있습니까 make -dnq ...?
  • 이 정보를 얻을 수 있는 더 좋은 방법이 있나요?
  • 이 정보를 구문 분석하기 위한 스크립트/시도가 이미 존재합니까?

답변1

노력하다makefile2graph같은 저자의 비슷한 도구가 있습니다MakeGraph종속성java대신에 로 작성되었습니다 c.

make -Bnd | make2graph | dot -Tsvg -o out.svg

그런 다음 벡터 그래픽 편집기를 사용하여 필요한 연결을 강조 표시합니다.

답변2

나는 사용했다리메이크 --프로필( 의 드롭인 대체품 make), callgrind 형식으로 종속성 트리를 생성했습니다.

그 다음에gprof2dot대상 트리의 이미지를 생성할 수 있습니다.

답변3

나는 어떤 대상이 어떤 전제 조건에 따라 달라지는지에 대해 최소한 명확하게 구조화된 정보를 출력하는 일종의 해킹을 발견했습니다. 단점은 상당히 방해가 된다는 점입니다. 즉, 모든 대상의 빌드 레시피를 작은 조건부 함수로 래핑하려면 makefile을 변경해야 합니다. 간단한 예를 게시하겠습니다.

getRecipe = $(if $(DEPENDENCY_GRAPH),@echo Target $@ depends on prerequisites "$^",$(1))


VARIABLE_TARGET_NAME = foobar.txt

all : TopLevelTarget

TopLevelTarget : Target_A Target_D
    $(call getRecipe,\
        @echo Building target $@)

Target_A : Target_B
    $(call getRecipe,\
        @echo Building target $@)

Target_D : Target_C
    $(call getRecipe,\
        @echo Building target $@)

Target_B : $(VARIABLE_TARGET_NAME)
    $(call getRecipe,\
        @echo Building target $@)

Target_C :
    $(call getRecipe,\
        @echo Building target $@)

$(VARIABLE_TARGET_NAME) :
    $(call getRecipe,\
        @echo Building target $@)

이 예에서는 손으로 만든 getRecipe 함수를 사용하여 각 개별 대상의 레시피를 래핑한 다음 해당 레시피를 실제로 실행할지 아니면 단순히 빌드 중인 대상과 해당 대상이 의존하는 전제 조건을 출력할지 결정합니다. 후자는 변수가 DEPENDENCY_GRAPH설정된 경우에만 발생합니다(예: 환경 변수). 예제에서 빌드 레시피는 대상이 빌드되고 있음을 알리는 에코에 불과하지만 이를 원하는 명령으로 대체할 수 있습니다.

1 로 DEPENDENCY_GRAPH설정하면 다음과 같은 결과가 출력됩니다.

Target foobar.txt depends on prerequisites ""
Target Target_B depends on prerequisites "foobar.txt"
Target Target_A depends on prerequisites "Target_B"
Target Target_C depends on prerequisites ""
Target Target_D depends on prerequisites "Target_C"
Target TopLevelTarget depends on prerequisites "Target_A Target_D"

구문 분석한 다음 도트 그래프로 변환하기가 충분히 쉬워야 합니다.

DEPENDENCY_GRAPH전혀 설정하지 않거나 0으로 설정하면 출력은 다음과 같습니다 .

Building target foobar.txt
Building target Target_B
Building target Target_A
Building target Target_C
Building target Target_D
Building target TopLevelTarget

즉, 일반 빌드 레시피가 대신 사용됩니다. 복잡한 레시피에서 이것이 안정적으로 작동하는지 아직 테스트하지 않았습니다. 내가 이미 겪은 한 가지 문제는 여러 줄의 레시피에서는 전혀 작동하지 않는다는 것입니다.

예를 들어, 마지막 대상의 빌드 레시피에서 대상이 빌드되고 있다고 말하는 것 외에도 실제로 touch파일을 원했다면 다음과 같습니다.

$(VARIABLE_TARGET_NAME) :
    $(call getRecipe,\
        @echo Building target $@\
        touch $@)

maketouch $@그 부분은 단지 이전 줄의 에코의 일부일 뿐이라고 생각하는 것 같습니다 .

Building target foobar.txt touch foobar.txt

이전 줄의 후행 백슬래시를 생략하면 call':missing을 make불평합니다 . 누군가 좋은 플레이 방법을 아는 사람이 있다면 모두 귀를 기울일 것입니다. :)*** unterminated call to function)'. Stop.make

편집: 이 접근 방식의 또 다른 문제는 빌드 결과가 이미 존재하지 않는 경우에만 작동한다는 것입니다. make분명히 최신으로 간주되는 대상의 빌드 레시피를 실행하지 않기 때문입니다.

답변4

특정 대상에 대한 종속성을 나열해야 하는 경우 다음 명령을 사용할 수 있습니다.

make -dn MAKE=: you_target | sed -rn "s/^ *Considering target file '(.*)'\.$/\1/p"

MAKE=:뛰지 않는 아이를 위한 것입니다만든다.

불행하게도 포함된 Makefile도 나열되어 있습니다. 당신은 할 수 있습니다그들을 필터링다음 쉘 스크립트 사용( list-deps):

#!/bin/sh -e

dbg="`make -dn "$@"`"
all="`echo -n "$dbg" | sed -rn "s/^ *Considering target file '(.+)'\.$/\1/p"`"
mks="`echo -n "$dbg" | sed -rn "s/^ *Reading makefile '([^']+)'.*$/\1/p"`"
echo -n "$all" | grep -vxF "$mks"

이제 다음 명령을 사용하여 대상에 대한 모든 종속성을 나열할 수 있습니다.

list-deps MAKE=: your_target

다시 작성해야 하는 종속성만 나열해야 하는 경우 다음을 참조하세요.이 답변.

편집: 이 답변을 찾는 다른 사람들을 위해 - 다음을 사용하여 들여쓰기를 유지할 수 있습니다.

make -dn MAKE=: you_target | sed -rn "s/^(\s+)Considering target file '(.*)'\.$/\1\2/p"

Makefile에서 이를 대상으로 만들 수도 있습니다.

.PHONY: graph 
graph: 
    make -dn MAKE=: all | sed -rn "s/^(\s+)Considering target file '(.*)'\.$/\1\2/p" 

관련 정보