Ignore warnings in external modules when using CMake - cmake

I am using CMake GUI (no version) with CMake 3.6.1. I am using an external module with add_subdirectory that shows me some warnings that I do not like (because of the annoying pollution):
CMake Warning (dev) at D:/Sources/.../external/g3log/latest/Build.cmake:11 (IF):
Policy CMP0054 is not set: Only interpret if() arguments as variables or
keywords when unquoted. Run "cmake --help-policy CMP0054" for policy
details. Use the cmake_policy command to set the policy and suppress this
warning.
Quoted variables like "MSVC" will no longer be dereferenced when the policy
is set to NEW. Since the policy is not set the OLD behavior will be used.
Call Stack (most recent call first):
D:/Sources/.../external/g3log/latest/CMakeLists.txt:72 (INCLUDE)
This warning is for project developers. Use -Wno-dev to suppress it.
I want to hide these warnings without touching the external files. -Wno-dev would be ok if it will affect only the external module (g3log).
I tried using cmake_policy like following with no effect:
cmake_policy(PUSH)
cmake_policy(SET CMP0054 OLD)
add_subdirectory(${g3log_DIR} ${CMAKE_BINARY_DIR}/../g3log)
cmake_policy(POP)

Turning my comments into an answer
That sounds like your external module does have a project() command. This resets the policies for this sub-module and below.
To demonstrate a possible solution, lets say you have a external project as the following:
g3log/CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(g3log NONE)
set(VAR1 "Hello World")
set(VAR2 "VAR1")
if ("${VAR2}" STREQUAL "${VAR1}")
message("CMP0054 old behavior")
endif()
You can now set CMAKE_POLICY_DEFAULT_CMP0054 to OLD (or even better to NEW; nobody really wanted the "OLD" behavior) to get rid of the "Policy CMP0054 is not set" warnings you will get with newer versions of CMake:
CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
project(PolicyOverwrite NONE)
set(CMAKE_POLICY_DEFAULT_CMP0054 NEW)
add_subdirectory(g3log)
Now you have set a default for policy CMP0054 to be used if none is explicitly given in your project or one of the external projects you are using.

Related

Why is the toolchain file executed a few times in CMake?

In an attempt to create a cross-compilation CMake toolchain template with the SDCC compiler, I have come across a very weird issue.
As described in this link, if the toolchain.cmake file defines a CMAKE_SYSTEM_NAME, CMake will look for the file with the ${CMAKE_SYSTEM_NAME}.cmake under the Module/Platform directory. And this file should define platform-specific options. In my case, I am using it to find the sdcc compiler and setting some compiler flags.
This works just fine for me. Using cmake -DCMAKE_MODULE_PATH="${PATH_TO_MY_MODULES}" -DCMAKE_TOOLCHAIN_FILE="${PATH_TO_MY_TOOLCHAIN}" -DSDCC_SYSROOT="SOME_VALUE", CMake finds all the correct toolchain and platform files.
It seems like the toolchain and the platform file are executed (not sure if that's the correct term) a few times during the configuration process. In the first few times, the variable SDCC_SYSROOT I passed in the CMake command has the value SOME_VALUE as expected. However, the same variable SDCC_SYSROOT seems to lose the value in the last time these toolchain/platform files are executed. So they are empty. This causes my script to generate a fatal error.
toolchain.cmake has the following contents:
set(CMAKE_SYSTEM_NAME SDCC_PIC_16F877A)
# Finding resource settings
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# Set default MCU family and model
if (NOT MICROCHIP_FAMILY)
set(MICROCHIP_FAMILY "pic16")
endif()
if (MICROCHIP_MODEL STREQUAL "pic16")
set(MICROCHIP_MODEL "16f877a")
endif()
# Need a better way to detect the supported models here
if (NOT MICROCHIP_FAMILY STREQUAL "pic16" AND NOT MICROCHIP_MODEL STREQUAL "16f877a")
message(FATAL_ERROR "Settings not supported. Please drop a request.")
endif()
if (NOT SDCC_ROOT)
message(FATA_ERROR "Need to provide the root (from toolchain.)")
endif()
# Cache those variables
set(SDCC_ROOT "${SDCC_ROOT}"
CACHE INTERNAL "Root directory of SDCC installation")
set(MICROCHIP_FAMILY "${MICROCHIP_FAMILY}"
CACHE INTERNAL "Family of the chip to compile for")
set(MICROCHIP_MODEL "${MICROCHIP_MODEL}"
CACHE INTERNAL "Model of the chip to compile for")
the Module/Platform/SDCC_PIC_16F877A.cmake file has the contents:
# Check if the shit exists
message("!!! The value of root is ${SDCC_ROOT}")
if (NOT SDCC_ROOT)
message(FATAL_ERROR
"SDCC_ROOT is not defined. Please set this variable e.g.\n"
"cmake -DSDCC_ROOT=\"C:/Program Files/sdcc\"")
endif()
# Finding the compilers
find_program(CMAKE_C_COMPILER
sdcc
PATHS ${SDCC_ROOT}
PATH_SUFFIXES "bin"
DOC "path to the SDCC C compiler.")
and my CMakeLists.txt is the following:
cmake_minimum_required(VERSION 3.10)
project(PicExample)
message("THE COMPILER IS ${CMAKE_C_COMPILER}")
add_executable(pic_example main.c)
what I invoke from my project/build directory and the error I get:
cmake -DCMAKE_MODULE_PATH:FILEPATH="/mnt/c/Users/mathe/Desktop/coding/sdcc-pic-template/Modules" -DCMAKE_TOOLCHAIN_FILE:FILEPATH="/mnt/c/Users/mathe/Desktop/coding/sdcc-pic-template/Modules/toolchain.cmake" -DSDCC_ROOT="testing/" ..
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
!!! The value of root is testing/
!!! The value of root is testing/
-- Check for working C compiler: /usr/bin/cc
FATA_ERRORNeed to provide the root (from toolchain.)
!!! The value of root is
CMake Error at /mnt/c/Users/mathe/Desktop/coding/sdcc-pic-template/Modules/Platform/SDCC_PIC_16F877A.cmake:4 (message):
SDCC_ROOT is not defined. Please set this variable e.g.
cmake -DSDCC_ROOT="C:/Program Files/sdcc"
Call Stack (most recent call first):
/usr/share/cmake-3.16/Modules/CMakeSystemSpecificInformation.cmake:26 (include)
/mnt/c/Users/mathe/Desktop/coding/sdcc-pic-template/build/CMakeFiles/CMakeTmp/CMakeLists.txt:3 (project)
CMake Error at /usr/share/cmake-3.16/Modules/CMakeTestCCompiler.cmake:44 (try_compile):
Failed to configure test project build system.
Call Stack (most recent call first):
CMakeLists.txt:2 (project)
-- Configuring incomplete, errors occurred!
See also "/mnt/c/Users/mathe/Desktop/coding/sdcc-pic-template/build/CMakeFiles/CMakeOutput.log".
Why do the toolchain files get "executed" more than once by CMake and has no access to cache in the latest runs? I've been finding CMake documentation for cross-compilation very difficult, especially if you are working with a non-standard compiler.
I am aware that other people have had same issues before, but I am not simply asking for a simple hacky solution (setting environment variables). I actually want to know why this happens (which the previous answers don't tackle).
Tsyvarev answered the why the toolchain is used multiple times in CMake. TLDR; CMake needs it for multiple try_compile() calls it uses internally for error checking and other things.
This works just fine for me.
-DCMAKE_MODULE_PATH="${PATH_TO_MY_MODULES}" -DCMAKE_TOOLCHAIN_FILE="${PATH_TO_MY_TOOLCHAIN}" -DSDCC_SYSROOT="SOME_VALUE",
To fix your problem here is what you need to do.
Essentially you are passing an argument to your toolchain file. And this argument SDCC_SYSROOT essentially goes out of scope.
To fix this problem here is what you need to do.
# Use list(APPEND) rather than set() so that any variables added by CMake aren't lost!
#
# Here is the docs for this variable:
# https://cmake.org/cmake/help/latest/variable/CMAKE_TRY_COMPILE_PLATFORM_VARIABLES.html
list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES ${SDCC_SYSROOT})
If you want to see how many times your toolchain script gets executed try putting in a message() call in there for fun.
And if you are really interested look inside your build folder and see what it is CMake is doing.
If you are wondering how I know this information it's because I read the toolchain section in Craig Scott's CMake book "Professional CMake:
A Practical Guide"
Here is a link: https://crascit.com/professional-cmake/
For determine, whether some feature is supported by the compiler or by some library, CMake uses try_compile approach: during the configuration phase, it creates separate CMake project and immediately configures and builds it. Because it is a separate project, its configuration has the same steps as the main project and it loads the toolchain file too.
try_compile could be used by the (user) project for check features of the library or of the compiler. There are many CMake modules which use try_compile in their implementation. E.g. CheckSymbolExists.
try_compile is also used by CMake itself, in platform files, when it perform basics checks for the compiler. In your log you could find the line:
CMake Error at /usr/share/cmake-3.16/Modules/CMakeTestCCompiler.cmake:44 (try_compile)
Aside from try_compile, the new CMake project is created in ExternalProject_Add command. That creation is also accompanied by the reading of the toolchain file. (More correctly, the new project is created not when ExternalProject_Add invocation is processed but when corresponding project is configured. This configuration is performed on the build stage of the main project.)

How to force cmake to use the new version of CMP0077 (allow options to be set from variables)

I'm trying to add Howard Hinnant's date library as a subdirectory of my build. Here's the simple setup:
$ git clone https://github.com/HowardHinnant/date.git
$ cat CMakeLists.txt
cmake_minimum_required(VERSION 3.18)
project(date_test)
set(BUILD_TZ_LIB ON)
set(USE_SYSTEM_TZ_DB ON)
set(ENABLE_DATE_TESTING OFF)
add_subdirectory(date)
Not much going on here. When I try to configure this build as-is, using cmake 3.18.3, I get a bunch of output like:
CMake Warning (dev) at date/CMakeLists.txt:30 (option):
Policy CMP0077 is not set: option() honors normal variables. Run "cmake
--help-policy CMP0077" for policy details. Use the cmake_policy command to
set the policy and suppress this warning.
For compatibility with older versions of CMake, option is clearing the
normal variable 'USE_SYSTEM_TZ_DB'.
This warning is for project developers. Use -Wno-dev to suppress it.
CMake Warning (dev) at date/CMakeLists.txt:34 (option):
Policy CMP0077 is not set: option() honors normal variables. Run "cmake
--help-policy CMP0077" for policy details. Use the cmake_policy command to
set the policy and suppress this warning.
For compatibility with older versions of CMake, option is clearing the
normal variable 'ENABLE_DATE_TESTING'.
This warning is for project developers. Use -Wno-dev to suppress it.
CMake Warning (dev) at date/CMakeLists.txt:37 (option):
Policy CMP0077 is not set: option() honors normal variables. Run "cmake
--help-policy CMP0077" for policy details. Use the cmake_policy command to
set the policy and suppress this warning.
For compatibility with older versions of CMake, option is clearing the
normal variable 'BUILD_TZ_LIB'.
This warning is for project developers. Use -Wno-dev to suppress it.
# date: USE_SYSTEM_TZ_DB OFF
# date: MANUAL_TZ_DB OFF
# date: USE_TZ_DB_IN_DOT OFF
# date: BUILD_SHARED_LIBS OFF
# date: ENABLE_DATE_TESTING OFF
# date: DISABLE_STRING_VIEW OFF
Notably, my variables got ignored (USE_SYSTEM_TZ_DB is OFF when I want it to be ON).
If I do what the error says, and add cmake_policy(SET CMP0077 NEW), then... I get the exact same thing. Same warning messages about the policy. Same ignoring of the variables I have set.
Is there a way to set these variables and have them propagate into the date build, or do I have to declare these as CACHE INTERNAL variables?
Setting the default value of that policy via set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) before the call to add_subdirectory that adds the date library to your project fixes the problem.
According to the documentation,
Commands cmake_minimum_required(VERSION) and cmake_policy(VERSION) by default leave policies introduced after the given version unset. Set CMAKE_POLICY_DEFAULT_CMP to OLD or NEW to specify the default for policy CMP, where is the policy number.
When CMAKE_POLICY_DEFAULT_CMP0077 is not set, the cmake_minimum_required(VERSION 3.7) call in the CMakeLists.txt of the date-library resets the value of that policy to the OLD behavior. If CMake didn't do that the build of a sub-project included via FetchContent or git submodules could easily break if the parent project updates their CMakeLists.txt to require a newer version.

Why emits CMake a CMP0022 warning although not using LINK_INTERFACE_LIBRARIES?

In my whole code I never use LINK_INTERFACE_LIBRARIES or something similar. All install, export and link_* command are used without.The only somewhat similar occurrence I was able to grep was in the build directory in the file lib/CMakeFiles/Export/lib/cmake/mylib-targets-noconfig.cmake:
IMPORTED_LINK_INTERFACE_LANGUAGES_NOCONFIG "CXX"
IMPORTED_LINK_INTERFACE_LIBRARIES_NOCONFIG
Still, I get a CMP0022 warning:
CMake Warning (dev) in lib/CMakeLists.txt: Policy CMP0022 is not set:
INTERFACE_LINK_LIBRARIES defines the link interface. Run "cmake
--help-policy CMP0022" for policy details. Use the cmake_policy command to set the policy and suppress this warning.
Target "mylib" has an INTERFACE_LINK_LIBRARIES property. This should
be preferred as the source of the link interface for this library but
because CMP0022 is not set CMake is ignoring the property and using
the link implementation as the link interface instead.
INTERFACE_LINK_LIBRARIES:
This happens when I link an external library to mylib. When I use CMake 2.8.12.1 which improved the handling of CMP0022 compared to 2.8.12 the number of warnings is massively reduced and I get only one warning per external library.
What causes the warning? From the documentation I don't get it.
What should I do to get rid of this warning? Is this compatible to older versions?
CMake 2.8.12.1 was released to address this issue. Please try that version.
In the meantime there was a similar question posted to the CMake mailing list. Stephen Kelly answered there are three options. [1, 2] The one I liked most uses LINK_PRIVATE and LINK_PUBLIC. But it is only backwards compatible to CMake 2.8.9.
Try putting this block:
IF(COMMAND CMAKE_POLICY)
CMAKE_POLICY(SET ???? OLD)
CMAKE_POLICY(SET ???? OLD)
ENDIF(COMMAND CMAKE_POLICY)
WHERE ???? is the name of the offending policy
I haven't read much about this yet, but I think is because they added a mechanism to set the target properties to avoid ambiguities when dealing with different targets, in any case, if a new version of CMake warns you about some policy you can set that policy to an old behavior.
https://cmake.org/cmake/help/v3.0/policy/CMP0022.html

CMake 2.8.10.1 treats debug/optimized as a relative directory

In my CMakeLists.txt, I have line 33:
link_directories (${QT_LIBRARIES})
where ${QT_LIBRARIES} expands to:
optimized;C:/QtSDK/Desktop/Qt/4.8.1/msvc2010/lib/QtOpenGL4.lib;debug;C:/QtSDK/Desktop/Qt/4.8.1/msvc2010/lib/QtOpenGLd4.lib
After an update to CMake 2.8.10.1, I get the following warning:
CMake Warning (dev) at CMakeLists.txt:33 (link_directories):
This command specifies the relative path
optimized
as a link directory.
Policy CMP0015 is not set: link_directories() treats paths relative to the
source dir. Run "cmake --help-policy CMP0015" for policy details. Use the
cmake_policy command to set the policy and suppress this warning.
This warning is for project developers. Use -Wno-dev to suppress it.
However, as you can see, ${QT_LIBRARIES} does not contain relative path.
In my opinion, CMP0015 policy is not relevant here.
Is it my mistake somewhere or is there a bug in CMake?
${QT_LIBRARIES} is a list of libraries, not library paths. It's designed to be used in target_link_libraries(). Replace your line 33 with:
targe_link_libraries(yourTargetName ${QT_LIBRARIES})
Note that use of link_directories() is discouraged in favour of full paths in target_link_libraries() anyway.

CMake on Linux: "target platform does not support dynamic linking"

I have the very simple CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
FIND_PACKAGE(VTK REQUIRED)
PROJECT(test CXX)
that really doesn't do anything. The package VTK is correctly found under /usr/lib/vtk-5.8/VTKConfig.cmake. This file includes a number of statements of the type
ADD_LIBRARY(foobar SHARED IMPORTED)
to indicate that the shared library libfoobar.so will need to be linked in executables.
Upon creating Makefiles using the above script, however, CMake will complain that
CMake Warning (dev) at /usr/lib/vtk-5.8/VTKTargets.cmake:244 (ADD_LIBRARY):
ADD_LIBRARY called with SHARED option but the target platform does not
support dynamic linking. Building a STATIC library instead. This may lead
to problems.
Call Stack (most recent call first):
/usr/lib/vtk-5.8/VTKConfig.cmake:200 (INCLUDE)
/usr/share/cmake-2.8/Modules/FindVTK.cmake:73 (FIND_PACKAGE)
CMakeLists.txt:4 (FIND_PACKAGE)
This warning is for project developers. Use -Wno-dev to suppress it
What does this warning mean and how is it dealt with?
This is a Linux system with CMake 2.8.9. While this error message appears for all packages that contain ADD_LIBRARY(foobar SHARED IMPORTED), VTK-5.8 is used as an example here.
PROJECT sets some important variables about the plarform.
Don't call FIND_* modules before setting a name to PROJECT.
This error message occurs when the CMake global property TARGET_SUPPORTS_SHARED_LIBS is set false and you use a shared library. See Source/cmAddLibraryCommand.cxx line 100 in the CMake source.
This shouldn't normally occur unless you are cross compiling for a very basic system (embedded OS).
I suspect that either this is a bug in the latest version of CMake or you have not configured CMake correctly.