본문 바로가기
CMake

[CMake] Policy

by 별준 2021. 11. 4.

References

  • Professional CMake : A Practical Guide

Contents

  • Policy
  • cmake_minimum_required(), cmake_policy()
  • Policy Scope

CMake는 새로운 기능들을 도입하고, 버그를 수정하고 특정 기능의 동작을 변경하면서 단점이 개선해나가며 오랫동안 발전해왔습니다. 새로운 기능의 도입은 이전 CMake 프로젝트에서 문제를 일으킬 가능성이 낮지만, 기존 기능이 변경되는 경우 프로젝트에 문제가 생길 수 있습니다.

 

이러한 이유로 이전 버전과 호환성을 유지하고자 간단한 마이그레이션 방법을 제공합니다. 이러한 제어는 CMake의 policy mechanisms을 통해 수행됩니다. 일반적으로 policy는 개발자가 자주 사용하는 것은 아니고, 대부분 이전 버전의 동작을 유지해야하는 프로젝트에서 노출됩니다.

 

CMake의 policy 기능은 cmake_minimum_required() 커맨드와 밀접하게 연결되어 있습니다. 이 커맨드는 프로젝트에 필요한 최소 CMake 버전을 지정할 뿐만 아니라 제공된 버전의 동작과 일치하도록 CMake의 동작을 설정합니다. 따라서 프로젝트가 cmake_minimum_required(VERSION 3.2)로 시작하면, 최소한 CMake 3.2버전이 필요하고 프로젝트는 3.2 릴리즈 버전으로 동작한다는 것을 의미합니다. 따라서, 개발자는 최신 버전의 CMake로 업데이트하더라도, 이전 프로젝트를 이전과 같이 빌드할 수 있습니다.

 

그러나 때때로, 다음과 같은 상황에서 cmake_minimum_reuiqred() 커맨드보다 더 세분화된 제어가 필요할 수 있습니다.

  • 프로젝트는 더 낮은 버전을 사용하지만, 높은 버전의 새로운 기능을 활용하고자 할 때
  • 프로젝트의 일부는 외부에서 읽기 전용 저장소에서 가져온 것이라 이전 버전의 CMake에 의존되지만, 프로젝트의 나머지 부분은 더 높은 버전을 사용하고자 할 때
  • 높은 버전의 CMake를 사용하기 위한 수정이 너무 많아서, 일부는 낮은 버전의 CMake 버전으로 유지하고자 할 때

위 예시들은 cmake_minimum_required() 커맨드만으로는 충분하지 않은 몇 가지 예시입니다. policy에 대한 세부적인 제어는 cmake_policy() 커맨드를 통해 활성화할 수 있습니다.

위 커맨드는 지정된 버전의 동작과 일치하도록 CMake의 동작을 변경합니다. cmake_minimum_required() 커맨드는 이 커맨드를 호출하여 CMake의 동작을 설정합니다. 최소 CMake 버전을 적용하기 위해 cmake_minimum_required()가 필수인 프로젝트의 시작부분을 제외하고는 두 커맨드는 서로 상호교환이 가능합니다. 일반적으로 최상위 CMakeLists.txt 파일의 시작을 제외하고는 cmake_policy()를 사용하여 아래 예제처럼 특정 버전의 동작을 적용합니다.

 

CMake 3.12에서는 단일 버전이 아닌 버전 범위를 지정하여 이전 버전과 호환되도록 할 수 있습니다. 범위는 공백없이 최소 버전과 최대 버전 사이에 3개의 점(...)을 사용하여 지정됩니다.

위의 예시는 CMake 3.7부터 CMake 3.12까지의 모든 policy에 대한 최신 동작을 지원합니다.

3.12 이전 버전의 CMake는 단일 버전만 확인하고 이후 '...3.12'는 무시합니다.

 

 

CMake는 SET 형식을 사용하여 각 동작을 개별적으로 제어하는 기능을 제공합니다.

각 개별 동작의 변경을 위해서는 CMPxxxx 형태의 CMake에서 고유한 policy 번호가 지정됩니다. 여기서 xxxx는 항상 4자리의 숫자입니다. NEW 또는 OLD를 지정하면 해당 특정 정책에 대해 새로운 동작 또는 이전 동작을 사용하도록 CMake에 지시합니다. (정책 링크 참조)

 

예를 들어, 3.0 이전에서는 CMake에서 프로젝트가 존재하지 않는 대상의 이름으로 get_target_property() 커맨드를 호출할 수 있었습니다. 이러한 경우 속성 값이 오류가 발생하지 않고 NOTFOUND와 같은 문자열로 반환되었지만, 프로젝트가 잘못되었을 가능성이 큽니다. 따라서 버전 3.0부터 이러한 상황이 발생하면 CMake는 오류와 함께 중지됩니다. 하지만, 프로젝트가 이전 동작에 의존하는 경우 다음과 같이 CMP0045를 설정하여 이전 동작을 유지할 수 있습니다.

policy를 NEW로 설정하는 경우는 흔하지 않습니다. 한 가지 가능한 상황은 프로젝트에서 최소 CMake 버전을 낮게 유지하지만, 이후 버전이 사용되는 경우 이후 버전의 기능을 활용하고자하는 경우입니다. 예를 들어, CMake 3.2에서 CMP0055 policy가 도입되어 break() 커맨드 사용에 대한 엄격한 체크가 적용되었습니다. 프로젝트가 여전히 이전 CMake 버전으로 빌드하는 것을 유지하면서 이후 버전의 policy를 다음과 같이 적용할 수 있습니다.

 

CMAKE_VERSION 변수를 체크하여 policy가 사용 가능한지 여부를 결정할 수 있지만, if(POLICY ...) 형식을 사용하면 보다 직관적으로 사용할 수 있습니다.

 

특정 policy의 현재 상태를 얻을 수도 있습니다. 현재 policy 설정을 읽어야 하는 대부분의 경우는 CMake 자체 또는 프로젝트에서 제공하는 모듈 파일에 있습니다. 프로젝트에서 정책 설정에 따라 동작을 변경하는 것은 거의 없다고 볼 수 있습니다.

위 명령은 CMPxxxx의 현재 상태를 읽어오고, outVar에 NEW, OLD 또는 빈 값으로 저장합니다.

 

cmake_minimum_required(VERSION ...) 및 cmake_policy(VERSION ...) 커맨드를 사용하면 모든 정책의 상태를 재설정합니다. 즉, 지정된 버전 이후에 추가된 정책들은 reset되어 비어있는 상태가 됩니다.

 

프로젝트를 진행하다보면 policy warning이 발생하여 해결해야하지만, 이 경고가 별로 바람직하지 않을 수 있습니다. 즉, 무시해도 되는 경고일 수 있습니다. 이를 처리하는 기본적인 방법은 policy를 원하는 동작(OLD 또는 NEW)으로 명시적으로 설정하여 경고를 끄는 것입니다. 그러나 프로젝트 내부에서 cmake_minimum_required(VERSION ...) 또는 cmake_policy(VERSION ...)를 사용하여 policy를 재설정하는 경우에는 위 방법이 불가능할 수 있습니다. 이러한 상황을 해결하기 위한 임시 방법으로 CMAKE_POLICY_DEFAULT_CMPxxxx 및 CMAKE_POLICY_WARNING_CMPxxx 변수를 설정할 수 있습니다. 이 변수들은 프로젝트에서 설정하는 것이 아니라 개발자가 일시적으로 캐시 변수로 설정하여 경고를 활성화/비활성화하거나 프로젝트에서 특정 정책이 활성화된 상태에서 경고를 출력하는지 여부를 확인하기 위한 것입니다. 궁극적인 해결책은 경고의 근본적인 문제를 해결하는 것입니다. 그럼에도 프로젝트에서 문제가 되지 않는 것으로 알려진 경고를 무시하는 것이 적절할 수도 있습니다.


Policy Scope

때때로 Policy는 특정 섹션에서만 적용되어야 합니다. 프로젝트에서 임시로 변경하려는 policy의 기본값을 편리하게 저장하고 복구할 수 있도록 CMake에서는 다음의 기능을 제공합니다.

모든 policy의 현재 상태는 PUSH 작업으로 저장할 수 있으며, 이전 상태를 POP으로 가져와서 현재 상태를 덮어쓸 수 있습니다.

 

policy가 암시적으로 PUSH되거나 POP될 수 있는데, 한 가지 예시가 add_subdirectory() 커맨드입니다. 해당 커맨드로 하위 디렉토리에 들어갈 때 스택에 현재 policy 상태를 PUSH하고, 디렉토리가 끝나서 반환될 때 POP 됩니다.

include() 커맨드 또한 지정된 파일 처리를 시작하기 전에 현재 policy scope를 PUSH하고 해당 파일의 처리가 완료되면 다시 POP합니다. find_package() 또한 include()와 유사하게 동작합니다.

 

include()와 find_package() 커맨드는 policy의 자동 PUSH/POP을 방지하는 NO_POLICY_SCOPE 옵션도 제공됩니다. 잘 사용되지는 않습니다. (add_subdirectory()에는 이러한 옵션이 없습니다.) 


개별 policy 설정이 가능하지만 가능한 프로젝트는 특정 policy를 조작하는 것보다 CMake 버전 수준에서 policy를 적용하는 것이 좋을 것 같습니다 !

'CMake' 카테고리의 다른 글

[CMake] Compiler and Linker 설정  (0) 2021.11.06
[CMake] Build Type / Custom Build Type  (0) 2021.11.05
[CMake] Modules  (6) 2021.11.04
[CMake] Generator Expressions  (0) 2021.11.03
[CMake] Properties  (0) 2021.11.02

댓글