GLOB로 소스 파일을 지정하는 것이 더 낫나요, 아니면 CMake에서 각 파일을 개별적으로 지정하는 것이 더 낫나요?

StackOverflow https://stackoverflow.com/questions/1027247

  •  06-07-2019
  •  | 
  •  

문제

CMake는 대상의 소스 파일을 지정하는 여러 가지 방법을 제공합니다.하나는 글로빙(선적 서류 비치), 예를 들어:

FILE (GLOB dir/*)

또 다른 방법은 각 파일을 개별적으로 지정하는 것입니다.

어떤 방법을 선호하나요?글로빙은 쉬운 것 같지만 몇 가지 단점이 있다고 들었습니다.

도움이 되었습니까?

해결책

전체 공개 : 나는 원래 단순성에 대한 글로브 접근 방식을 선호했지만, 수년에 걸쳐 파일을 명시 적으로 나열하는 것이 대규모 다중 개발자 프로젝트의 오류가 덜되었다는 것을 인식하게되었습니다.

원래 답변 :


글로브의 장점은 다음과 같습니다.

  • 디스크에서 한 곳에서만 나열되어 있으므로 새 파일을 추가하기 쉽습니다. Globbing은 복제를 만듭니다.

  • cmakelists.txt 파일이 짧아집니다. 파일이 많으면 큰 장점입니다. Globbing이 아닌 큰 파일 목록 중에서 Cmake 논리를 잃게됩니다.

하드 코딩 된 파일 목록을 사용하는 장점은 다음과 같습니다.

  • Cmake는 디스크에서 새 파일의 종속성을 올바르게 추적합니다. Glob를 사용하면 Cmake를 실행할 때 처음으로 Globbed가 아닌 파일을 사용하지 않습니다.

  • 원하는 파일 만 추가해야합니다. Globbing은 원하지 않는 길 잃은 파일을 선택할 수 있습니다.

첫 번째 문제를 해결하려면 터치 명령을 사용하거나 변경없이 파일을 작성하여 글로벌을하는 cmakelists.txt를 "터치"할 수 있습니다. 이로 인해 Cmake가 새 파일을 다시 실행하고 선택해야합니다.

두 번째 문제를 해결하려면 코드를 디렉토리로 신중하게 구성 할 수 있습니다. 최악의 경우 목록 (remove_item) 명령을 사용하여 글로브 파일 목록을 정리할 수 있습니다.

file(GLOB to_remove file_to_remove.cpp)
list(REMOVE_ITEM list ${to_remove})

이것이 당신을 물릴 수있는 유일한 실제 상황은 당신이 같은 것을 사용하는 것입니다. git-bisect 동일한 빌드 디렉토리에서 이전 버전의 코드를 시도합니다. 이 경우 목록에 올바른 파일을 얻기 위해 필요한 것보다 더 많이 청소하고 컴파일해야 할 수도 있습니다. 이것은 코너 케이스이며, 당신이 이미 발가락에있는 곳으로, 실제로는 문제가되지 않습니다.

다른 팁

cmake에서 sourcefiles를 지정하는 가장 좋은 방법은 다음과 같습니다. 명시 적으로 나열합니다.

CMake 자체의 제작자는 조언합니다 ~ 아니다 글로브를 사용합니다.

보다: http://www.cmake.org/cmake/help/v3.3/command/file.html?highlight=glob#file

(소스 트리에서 소스 파일 목록을 수집하기 위해 Glob을 사용하지 않는 것이 좋습니다. cmakelists.txt 소스가 추가되거나 제거되면 변경되지 않으면 생성 된 빌드 시스템은 CMAKE에게 재생을 요청 해야하는시기를 알 수 없습니다).

물론, 당신은 단점이 무엇인지 알고 싶을 수도 있습니다. 읽어!


글로브가 실패 할 때 :

글로브의 큰 단점은 파일 생성/삭제가 빌드 시스템을 자동으로 업데이트하지 않는다는 것입니다.

파일을 추가하는 사람이라면, 이것은 허용 가능한 트레이드 오프처럼 보일 수 있지만, 이로 인해 코드를 구축하는 다른 사람들에게 문제가 발생하고 버전 제어에서 프로젝트를 업데이트하고 빌드를 실행 한 다음 연락하여 연락하여 불만을 제기합니다.
"빌드가 깨졌다".

설상가상으로, 실패는 일반적으로 문제의 원인에 대한 힌트를주지 않는 링크 오류를 제공하며 시간이 문제 해결을 잃어 버립니다.

내가 작업 한 프로젝트에서 우리는 Globbing을 시작했지만 새 파일이 추가 될 때 많은 불만을 얻었으므로 Globbing 대신 파일을 명시 적으로 나열해야 할 충분한 이유였습니다.

이것은 또한 일반적인 git 작업 흐름을 깨뜨립니다
(git bisect 기능 분기 사이에서 전환).

그래서 나는 이것을 추천 할 수 없었습니다. 문제가 편의성보다 훨씬 높습니다. 누군가가 이로 인해 소프트웨어를 구축 할 수 없을 때 문제를 추적하거나 포기하는 데 많은 시간이 걸릴 수 있습니다.

그리고 또 다른 메모, 만지는 것을 기억합니다 CMakeLists.txt 항상 충분하지는 않지만 Globbing을 사용하는 자동화 된 빌드를 사용하면 실행해야했습니다. cmake ~ 전에 모든 빌드 파일 이후 ~할 것 같다 마지막 건물 이후에 추가/제거되었습니다.

규칙에 대한 예외 :

글로브가 바람직한 시간이 있습니다.

  • 설정을 위해 CMakeLists.txt CMAKE를 사용하지 않는 기존 프로젝트의 파일.
    모든 소스를 참조 할 수있는 빠른 방법입니다 (빌드 시스템이 실행되면 Globbing을 명시 적 파일 목록으로 대체하십시오).
  • cmake가 사용되지 않을 때 일 순위 빌드 시스템, 예를 들어 CMAKE를 사용하지 않는 프로젝트를 사용하고 있으며 자신의 빌드 시스템을 유지하고 싶습니다.
  • 파일 목록이 너무 자주 변경되는 상황에서는 유지 관리가 실용적이지 않습니다. 이 경우 ~할 수 있었다 유용하지만 달리기를 받아 들여야합니다. cmake 빌드 파일을 생성합니다 매번 신뢰할 수있는/올바른 빌드를 얻으려면 (CMAKE의 의도에 위배되는 것 - 구성에서 구성을 분할하는 능력).

* 그렇습니다. 업데이트 전후 디스크의 파일 트리를 비교하기위한 코드를 작성할 수 있었지만 이는 좋은 해결 방법이 아니며 빌드 시스템에 남은 것이 더 나은 것이 아닙니다.

종속성을 유지하기 위해 추가 파일을 사용하여 안전하게 glob할 수 있습니다(아마도 그렇게 해야 합니다).

다음과 같은 기능을 어딘가에 추가하세요.

# Compare the new contents with the existing file, if it exists and is the 
# same we don't want to trigger a make by changing its timestamp.
function(update_file path content)
    set(old_content "")
    if(EXISTS "${path}")
        file(READ "${path}" old_content)
    endif()
    if(NOT old_content STREQUAL content)
        file(WRITE "${path}" "${content}")
    endif()
endfunction(update_file)

# Creates a file called CMakeDeps.cmake next to your CMakeLists.txt with
# the list of dependencies in it - this file should be treated as part of 
# CMakeLists.txt (source controlled, etc.).
function(update_deps_file deps)
    set(deps_file "CMakeDeps.cmake")
    # Normalize the list so it's the same on every machine
    list(REMOVE_DUPLICATES deps)
    foreach(dep IN LISTS deps)
        file(RELATIVE_PATH rel_dep ${CMAKE_CURRENT_SOURCE_DIR} ${dep})
        list(APPEND rel_deps ${rel_dep})
    endforeach(dep)
    list(SORT rel_deps)
    # Update the deps file
    set(content "# generated by make process\nset(sources ${rel_deps})\n")
    update_file(${deps_file} "${content}")
    # Include the file so it's tracked as a generation dependency we don't
    # need the content.
    include(${deps_file})
endfunction(update_deps_file)

그런 다음 글로빙을 해보세요.

file(GLOB_RECURSE sources LIST_DIRECTORIES false *.h *.cpp)
update_deps_file("${sources}")
add_executable(test ${sources})

이전과 같이 여전히 명시적인 종속성을 다루고 있으며 모든 자동화된 빌드를 트리거하고 있습니다. 파일은 하나가 아닌 두 개뿐입니다.

절차의 유일한 변경 사항은 새 파일을 만든 후에입니다.glob을 수행하지 않는 경우 워크플로는 Visual Studio 내부에서 CMakeLists.txt를 수정하고 다시 빌드하는 것입니다. glob을 수행하는 경우 명시적으로 cmake를 실행하거나 CMakeLists.txt를 터치하면 됩니다.

CMake 3.12에서는 file(GLOB ...) 그리고 file(GLOB_RECURSE ...) 명령을 얻었습니다 CONFIGURE_DEPENDS glob의 값이 변경되면 cmake를 다시 실행하는 옵션입니다.이것이 소스 파일 글로빙의 주요 단점이었으므로 이제는 그렇게 해도 괜찮습니다.

# Whenever this glob's value changes, cmake will rerun and update the build with the
# new/removed files.
file(GLOB_RECURSE sources CONFIGURE_DEPENDS "*.cpp")

add_executable(my_target ${sources})

그러나 일부 사람들은 여전히 ​​소스 글로빙을 피하는 것을 권장합니다.물론, 문서 상태:

소스 트리에서 소스 파일 목록을 수집하기 위해 GLOB를 사용하지 않는 것이 좋습니다....그만큼 CONFIGURE_DEPENDS 플래그는 모든 생성기에서 안정적으로 작동하지 않을 수 있습니다. 또는 나중에 이를 지원할 수 없는 새 생성기가 추가되면 이를 사용하는 프로젝트가 중단됩니다.설사 CONFIGURE_DEPENDS 안정적으로 작동하더라도 재구축할 때마다 검사를 수행하는 데 여전히 비용이 듭니다.

개인적으로 나는 가능한 단점보다 소스 파일 목록을 수동으로 관리할 필요가 없다는 이점이 더 크다고 생각합니다.수동으로 나열된 파일로 다시 전환해야 하는 경우 글로브된 소스 목록을 인쇄하고 다시 붙여넣기만 하면 쉽게 전환할 수 있습니다.

각 파일을 개별적으로 지정하십시오!

기존의 cmakelists.txt와 Python 스크립트를 사용하여 업데이트합니다. 파일을 추가 한 후 Python 스크립트를 수동으로 실행합니다.

내 대답을 참조하십시오.https://stackoverflow.com/a/48318388/3929196

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top