GraphViz를 CMake 및 Clang과 함께 사용하는 서예

Nov 24 2020

내 목표는 빌드 타임에 CMake + Clang + GraphViz를 사용하여 호출 그래프를 생성하는 것입니다.

이러한 [ 1 , 2 ] 프로세스를 사용하여 간단한 그래프를 만들 수 있습니다. 그러나 프로세스를 CMake 프로젝트로 일반화하는 방법을 모르겠습니다.

실행 가능한 대상이 있습니다.

add_executable(${TARGET} ${SOURCES})

매크로 내에서 대상에 그래프 관련 옵션을 추가합니다.

target_compile_options(${TARGET} PRIVATE -S -emit-llvm)

그리고 호출 그래프를 생성하는 추가 빌드 후 명령을 추가합니다.

add_custom_command(
    TARGET ${TARGET}
    POST_BUILD
    COMMENT "Running clang OPT"
    COMMAND opt -analyze -dot-callgraph
)

그러나 clang은 대상에 대한 실행 파일을 만들려고합니다. 이로 인해 다음 오류가 발생합니다.

[build] lld-link: error: 
Container.test.cpp.obj: unknown file type

또한 사용자 지정 명령 ( opt예 :)이 생성 된 LLVM 표현에 액세스하는 방법을 이해하지 못합니다 . 내 사용자 지정 명령에 관련 파일에 대한 지식이없는 것 같습니다 (위의 오류가 수정 된 경우에도).


내가 지금까지 이해 한 것 :

  1. CMake add_executable-o outfile.execlang에 인수를 추가하면 연결된 프로세스 [ 1 , 2 ]에 표시된 동일한 단계를 수행 할 수 없습니다 .
  2. $<TARGET_FILE:${TARGET}> clang에서 생성 된 파일을 찾는 데 사용할 수 있지만 이것이 LLVM 표현에 대해 작동하는지 모르겠습니다.
  3. 대신 사용자 지정 대상을 시도했지만 TARGET모든 설정이 포함 된 모든 소스를 사용자 지정 대상으로 가져 오는 데 문제가있었습니다 .
  4. 여기에 설명 된 프로세스 [ 3 ]는 특별히 관련 -Wl,-save-temps이 있을 수 있지만 이것은 IR (llvm-dis 사용)을 얻는 꽤 우회적 인 방법 인 것 같습니다.
  5. unknown file type오류는 개체가 실제로 LLVM표현 되기 때문 이지만 링커가 다른 형식을 기대한다고 생각합니다.
  6. 링커가 LLVM표현 을 이해 -flto하도록하려면 링커 옵션에 추가하십시오 target_link_options(${TARGET} PRIVATE -flto)(소스 [ 4 ]). 이것은 내가 거의 해결했음을 의미하기 때문에 굉장합니다 ... cmake에서 생성 된 비트 코드 출력 파일의 경로를 얻는 방법을 모르겠습니다. 만약 한 번 선택하면 전달할 수 있습니다. ..).
  7. 대상을 얻으려면 다음 cmake 명령을 사용할 수있는 개체를 $<TARGET_OBJECTS:${TARGET}>대상 목록 것이 cmake의 경우 .o(은 IS .o때문에 cmake로 이름 변경의?) LLVM의 비트 코드 파일.
  8. .o이 경우 파일은 그러나, 비트 코드이다 opt도구 만 LLVM 표현으로 나타납니다. 이 llvm-dis bitcode.bc –o llvm_asm.ll. 크로스 컴파일로 인해 엉망이 된 기호가 이상한 형식이라고 생각합니다. llvm-cxxfilt예를 들어, 그들을 전달하는 것은 성공하지 못합니다.llvm-cxxfilt --no-strip-underscore --types ?streamReconstructedExpression@?$BinaryExpr@AEBV?$reverse_iterator@PEBD@std@@AEBV12@@Catch@@EEBAXAEAV?$basic_ostream@DU?$char_traits@D@std@@@std@@@Z
  9. 그래서 주소 8. 이것은 MSVC 이름 맹 글링 형식입니다. 이는 Windows clang에서 컴파일 할 때 MSVC 형식 이름 맹 글링을 사용함을 나타냅니다. 놀랍습니다 ... (출처 [ 5 ]).
  10. LLVM llvm-undname은 기호를 엉망으로 만들 수 있습니다. 이 도구를 실행하면 원시 입력을 할 때 오류가 크게 발생하며 올바른 기호로만 작동하는 것 같습니다. 이 도구 demumble는 크로스 플랫폼, llvm-undname 및 llvm-cxxfilt의 다중 형식 래퍼로 보입니다.

11. 거의 작동하는 cmake 매크로는 다음과 같습니다.

macro (add_clang_callgraph TARGET)
    if(CALLGRAPH)
        target_compile_options(${TARGET} PRIVATE -emit-llvm)
        target_link_options(${TARGET} PRIVATE -flto) foreach (FILE $<TARGET_OBJECTS:${TARGET}>) add_custom_command( TARGET ${TARGET}
                POST_BUILD
                COMMAND llvm-dis ${FILE} COMMAND opt -dot-callgraph ${FILE}.ll
                COMMAND demumble ${FILE}.ll.callgraph.dot > ${FILE}.dot
            )
        endforeach()
    endif()
endmacro()

그러나 이것은 작동하지 않습니다 ...의 내용 ${FILE}은 항상 전체 목록입니다 ...

이것은 여전히 ​​여기에 해당됩니다.

foreach (FILE IN LISTS $<TARGET_OBJECTS:${TARGET}>) add_custom_command( TARGET ${TARGET}
        POST_BUILD
        COMMAND echo ${FILE}
    )
endforeach()

결과는 다음과 같습니다.

thinga.obj;thingb.obj

이는 CMake가 for 루프가 평가 될 때까지 생성기 표현식을 평가하지 않기 때문입니다. 의미, 여기에는 루프가 하나만 있고 생성기 표현식 (해결 된 생성기 표현식이 아님)이 포함되어 있습니다 (소스 [ 6 ]). 즉, 개체 파일을 반복하고 각 개체 파일에 대해 일련의 사용자 지정 명령을 만들 수 없습니다.


제가 알아 낸대로 위에 추가하겠습니다. 전체 프로세스를 파악하면 솔루션을 게시하겠습니다.

어떤 도움이라도 대단히 감사하겠습니다. 이것은 엉덩이에 큰 고통이었습니다.


내가 바라는 것은 CMake가 단일 LLVM 표현 파일에 대한 실행 파일 빌드를 허용하고 해당 파일을 opt와 함께 사용하여 콜 그래프를 얻은 다음 llc. 나는 크로스 컴파일을 할 때 약간 제약이 있습니다. 궁극적으로 동등한 것은 무엇이든 할 것입니다 ...

답변

1 compor Nov 24 2020 at 20:26

지금까지의 모든 댓글 응답을 수집하기 위해 답변을 시도하겠습니다.

당신이 "파괴"CMake하려는 경우, (에서 적응이 같은 수행 할 수 있습니다 여기 영업 이익의 점 4 위 밖으로) :

cmake_minimum_required(VERSION 3.0.2)

project(hello)

set(CMAKE_C_COMPILER clang)
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} "-flto") add_executable(hello main.c hello.c) # decide your bitcode generation method here # target_compile_options(hello PUBLIC ${CMAKE_C_FLAGS} -emit-llvm)
target_compile_options(hello PUBLIC ${CMAKE_C_FLAGS} -c -flto) # this is just to print add_custom_target(print_hello_objs COMMAND ${CMAKE_COMMAND} -E echo $<JOIN:$<TARGET_OBJECTS:hello>," ">)

# this does some linking
# fill in details here as you need them (e.g., name, location, etc.)
add_custom_target(link_hello_objs 
  COMMAND llvm-link -o foo.bc $<TARGET_OBJECTS:hello> 
  COMMAND_EXPAND_LISTS)

각 파일에 대한 처리가 필요한 COMMAND경우은 목록을 가져와 .dot 파일을 생성하는 외부 스크립트 (bash / python) 일 수 있습니다. 생성기 표현식의 문제는 foreach컨텍스트가 아닌 CMake에서 생성 시간까지 평가되지 않는다는 것입니다 .

재 컴파일 된 객체 / 비트 코드 파일을 기반으로 재생성을 트리거하려는 경우 CMake가 도구 체인의 구성 요소 (컴파일러, 링크 등)를 호출하는 미리 설정된 방법을 가지고 있기 때문에 문제가 발생하므로 CMake 기반 프로젝트를 다시 작성했습니다. 그러나 나는 당신이 아직 무엇을 상대하고 있는지 확실하지 않은 것처럼 들리므로 처음에는 과도한 엔지니어링을 피하는 것이 좋습니다.

이 기계 ATM에 그런 설정이 없기 때문에 실행 가능한 실행 파일을 얻기 위해 LTO가 완전히 작동하도록 만드는 데 신경 쓰지 않았습니다 .

다른 모든 요구 사항 (예 : Graphviz 출력, 디맨 글링)은 추가 사용자 지정 대상 / 명령과 연결할 수 있습니다.

다른 솔루션은 다음과 같습니다.

  1. gllvm
  2. 절망적 인 llvm-ir-cmake-utils를 위해