Can I cause a CMake internal error? - cmake

Following my question What can cause a CMake option not work? I attempted to find out whether there is any difference between using clean-all.cmake and manually deleting the build directory. After running clean-all, I still experience the option problem. When I remove the build subdirectory, I receive the error message below:
-- Looking for include file pthread.h
-- Looking for include file pthread.h - not found
CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage
CMake Error: Internal CMake error, TryCompile configure of cmake failed
CMake Error at /usr/local/share/cmake-3.2/Modules/FindPackageHandleStandardArgs.cmake:138 (message):
Could NOT find Threads (missing: Threads_FOUND)
Call Stack (most recent call first):
/usr/local/share/cmake-3.2/Modules/FindPackageHandleStandardArgs.cmake:374 (_FPHSA_FAILURE_MESSAGE)
/usr/local/share/cmake-3.2/Modules/FindThreads.cmake:204 (FIND_PACKAGE_HANDLE_STANDARD_ARGS)
cmake/Dependencies.cmake:11 (find_package)
CMakeLists.txt:53 (include)
and the log file only contains:
Determining if files pthread.h exist failed with the following output:
Source:
/* */
#include <pthread.h>
int main(void){return 0;}
And, since that, the system keeps telling that error. So, it looks like there is a difference :) ; what is it? Is it possible that my CMakeLists.txt leads to some internal error?
PS: After having this permanent error, I started to look for its reason, building up my CMakeLists.txt again, starting with deleted build subdirectory.
At the beginning, I have
option (CLEAN_ALL "Make a cleanup before building" OFF)
later
if(CLEAN_ALL)
include(cmake/clean-all.cmake)
endif(CLEAN_ALL)
and the cmake file is
# clean-all.cmake
# Cleans all subdirectories in the build subdirectory
set(cmake_generated ${CMAKE_BINARY_DIR}/CMakeCache.txt
${CMAKE_BINARY_DIR}/cmake_install.cmake
${CMAKE_BINARY_DIR}/Makefile
${CMAKE_BINARY_DIR}/CMakeFiles
# Above this, the common directories, below the project-specific ones
${CMAKE_BINARY_DIR}/bin
${CMAKE_BINARY_DIR}/lib
${CMAKE_BINARY_DIR}/QtGUI
${CMAKE_BINARY_DIR}/test
)
foreach(file ${cmake_generated})
if (EXISTS ${file})
file(REMOVE_RECURSE ${file})
endif()
endforeach(file)
It looks like the error is reproducible: deleting build and switching the option ON, I receive the error mentioned. At the same time, with option OFF, it builds OK. Is there anything harmful with using that clean-all?

CMake stores the state of the project built as files in the build directory for the project. These files are not protected, so improper modification of them (like deleting) may cause state of the project to become non-consistent.
Message Internal CMake error means that this is (probably) an error within CMake if project build files, generated by CMake, are not corrupted outside.
Otherwise, such an error just signals that the project build is broken somehow.
In the given case, the inconsistent state is caused by deleting file CMakeCache.txt during CMake invocation. The answer which is origin of your clean- all.cmake script explicitly says that after calling this script no CMake command will work.

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 do I get a verbose output for CMake?

I would like to investigate why I have this error:
$ cmake ..
-- The C compiler identification is unknown
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /cygdrive/c/Users/Ycr/Home/bin/arm-none-eabi-gcc
-- Check for working C compiler: /cygdrive/c/Users/Ycr/Home/bin/arm-none-eabi-gcc -- broken
CMake Error at /usr/share/cmake-3.6.2/Modules/CMakeTestCCompiler.cmake:61 (message):
The C compiler "/cygdrive/c/Users/Ycr/Home/bin/arm-none-eabi-gcc" is not
able to compile a simple test program.
Unfortunately after the error:
I have no idea of what CMake did. I don't have a verbose log of the command it executed.
The CMakeFiles/cmTC_e4aa4.dir was cleaned after the error, so I have no possibility to explore the issue myself.
How should I investigate such an error?
I tried to use the --debug-trycompile option. This time CMake creates a CMakeTmp folder which makes perfectly without errors. However, I still have this CMakeFiles/cmTC_e4aa4.dir that generates errors and even with the option CMake unlinks the folder.
Getting a Verbose Log
The try_compile() calls that CMake does in the beginning to test the compiler, gives a detailed error output on the console and writes it to
[your binary output directory]/CMakeFiles/CMakeError.log
I've checked the source code again and there is no CMake option that would give more a more detailed output for CMake's internal try_compile() calls.
You could just force the output to standard output by adding some variable_watch() calls to your main CMakeLists.txt before your project() call like:
variable_watch(__CMAKE_C_COMPILER_OUTPUT)
variable_watch(__CMAKE_CXX_COMPILER_OUTPUT)
Keeping the Temporary Files
To keep the temporary file of try_compile, add --debug-trycompile to the cmake command line.
But be aware that the multiple compiler tests at the beginning overwrite the artifacts of previous ones:
It may however change the results of the try-compiles as old junk from a previous try-compile may cause a different test to either pass or fail incorrectly. This option is best used for one try-compile at a time, and only when debugging.
References
How to keep generated temporary files?
CMake error at CMakeLists.txt:30 (project): No CMAKE_C_COMPILER could be found
For me, none of the log files in my output directory contained useful information from try_compile(), even when using --debug-trycompile.
I ended up using the OUTPUT_VARIABLE option to capture and then print the output like this:
try_compile(<options> OUTPUT_VARIABLE TRY_COMPILE_OUTPUT)
message(WARNING ${TRY_COMPILE_OUTPUT})

Custom path for my libraries for find_library

I am trying to compile openimageio(oiio) on Linux but it's a mess since I know almost nothing about cmake. I don't want and I can't install them on my computer directly in the /usr/local/ directory and that's the problem. I successfully compiled dependencies by executing these bash commands in each library directory :
export workingdir=<path_to_my_project>
./configure --prefix=$workingdir/sdks/deploy
make install
And this works fine, my headers are in a include directory and my libraries are in a lib directory.
Here is the structure of my project :
../<path_to_my_project>
/sdks
/build
/oiio
/png # Successfully compiled
/jpeg # Successfully compiled
/zlib # Successfully compiled
/boost # Successfully compiled
/ilmbase # Successfully compiled
/openexr # Successfully compiled
/deploy
/lib # all .a, .la and .so of successfully compiled libraries
/include # all headers of successfully compiled libraries
The problem is that there is no ./configure available in the oiio library directory so I don't know how to set the prefix path, when I execute the make command, I have errors like this :
CMake Error at /usr/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:108 (message):
Could NOT find PNG (missing: PNG_LIBRARY) (found version "1.6.21")
Call Stack (most recent call first):
/usr/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:315 (_FPHSA_FAILURE_MESSAGE)
/usr/share/cmake/Modules/FindPNG.cmake:105 (find_package_handle_standard_args)
src/libOpenImageIO/CMakeLists.txt:120 (find_package)
So I set variables and it makes no errors but this is not clean and I'm not sure that my libraries are correctly referenced (If I mes up the variable content, it is still working...).
set (PNG_PNG_INCLUDE_DIR "<workingdir>/sdks/deploy/include/libpng16")
set (PNG_LIBRARY_DIR "<workingdir>/sdks/deploy/lib")
Then I tried to create my own FindXXX.cmake files but some don't have a Root variable for the library so anyway I'm not sure if it correctly found the needed files, moreover, it makes errors :
CMake Error at src/cmake/modules/FindPNG.cmake:104 (include):
include could not find load file:
<workingdir>/sdks/build/oiio/src/cmake/modules/FindPackageHandleStandardArgs.cmake
Call Stack (most recent call first):
src/libOpenImageIO/CMakeLists.txt:120 (find_package)
But it finds the cmake file it anyway since other errors are correctly referenced to my file and if I print something in the cmake file it shows up when I run the make command.
Up to know, the command I am running in the oiio directory is make but I would like something that tells to the find_library function to looks other where. I could recall the function with other parameters but I can't use my own FindXXX.cmake files.
In the oiio repository, in the INSTALL file, paragraph line 43, it says to set environment variable for custom libraries, like PNGDIR, but should it point to the deploys directory or the build directory ? And they say to see CMake configuration output, maybe to know what environment variables to set, but I don't know what file they are talking.
I tried so set PNGDIR but it doesn't work, how to know if the variable name should be PNGDIR ? It can also be PNGROOT ?
export PNGDIR=<workingdir>/sdks/deploy # doesn't work
export PNGDIR=<workingdir>/sdks/build/png # doesn't work
It would be nice if someone could help me, I need this library to be compiled to use it, hope someone understood me.
Use CMAKE_PREFIX_PATH to indicate paths where find_library, find_path et al. should have a look (documentation)
Stuff like PNGDIR should no longer be used and is considered legacy that is kept for backwards compatibility. Patches for FindXXX provided by CMake to add XXX_DIR or XXX_ROOT are rejected by the CMake developers.

Building a VS2015 x64 project using glew 1.13.0 and CMake 3.4.0

How do I build a VS2015 x64 project using glew 1.13.0 and CMake 3.4.0?
I prepared a minimal demo that can be found here: https://bitbucket.org/Vertexwahn/cmakedemos/src/2fbbc02b2c0567319d7be070b34391b1ef35048d/GlewDemo/?at=default
CMakeLists.txt:
cmake_minimum_required ( VERSION 2.8)
project ( GlewDemo )
find_package(GLEW REQUIRED)
set ( SRCS main.cpp )
add_executable(GlewDemo ${SRCS})
target_link_libraries(GlewDemo glew32s)
I downloaded the prebuilt binaries from here: http://sourceforge.net/projects/glew/files/glew/1.13.0/glew-1.13.0-win32.zip/download
And set the path of GLEW_INCLUDE_DIR to the corresponding directory ("C:\Users\no68koc\Downloads\glew-1.13.0\include")
But CMake gives me some errors:
CMake Error at C:/Program Files (x86)/CMake/share/cmake-3.4/Modules/FindPackageHandleStandardArgs.cmake:148 (message):
Could NOT find GLEW (missing: GLEW_LIBRARY)
Call Stack (most recent call first):
C:/Program Files (x86)/CMake/share/cmake-3.4/Modules/FindPackageHandleStandardArgs.cmake:388 (_FPHSA_FAILURE_MESSAGE)
C:/Program Files (x86)/CMake/share/cmake-3.4/Modules/FindGLEW.cmake:44 (find_package_handle_standard_args)
CMakeLists.txt:4 (find_package)
Configuring incomplete, errors occurred!
See also "C:/build/vs2015/GlewDemo/CMakeFiles/CMakeOutput.log".
How does it work properly?
Error message
Could NOT find GLEW (missing: GLEW_LIBRARY)
is a standard message generated by FindXXX.cmake script (called via find_package(XXX)), that it is failed to set(deduce) some CMake variables, so whole package is assumed to be not found.
Most of FindXXX.cmake scripts descibes(in the comment), which variables are set by the script for user.
But only several of them describes, how user can help script in case when the script failed to find needed package at all, or if user wants script to find specific package installation instead of default one.
There is no universal approach in helping to the FindXXX.cmake script, in most cases one should analize code of the script for know variables, which can help.
In the given case (with GLEW package) analizing CMake-provided FindGLEW.cmake script reveals, that both find_path() call (which set GLEW_INCLUDE_DIR variable) and find_library() call (which set GLEW_LIBRARY variable) use no hints (HINT or PATH options) for search. But there are standard hints, which are used by both of this commands. One of these hints is ${CMAKE_PREFIX_PATH}/include directory for find_path and similar directory for find_library.
So you can use
list(APPEND CMAKE_PREFIX_PATH "C:\Users\no68koc\Downloads\glew-1.13.0")
for hint to find_library() and find_path() to search under this directory too.
Alternatively, you may set CMAKE_PREFIX_PATH variable in CMake cache either in GUI (e.g. inside Visual Studio) or via command line:
cmake -DCMAKE_PREFIX_PATH:PATH=C:\Users\no68koc\Downloads\glew-1.13.0
(Note, that using list(APPEND ...) instead of set(...) within CMakeLists.txt does not override variable in case it is set in cache too).
You may use another, 3d-party FindGLEW.cmake script
You can download it into your project (e.g., to cmake/FindGLEW.cmake) and issue
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
for tell find_package() to use this script instead of default one.
Given script uses
${GLEW_LOCATION}
directory (and its subdirectories) as hint for searching in find_path() and find_library() (under PATH command's option). So you can set GLEW_LOCATION variable to installation directory:
set(GLEW_LOCATION "C:\Users\no68koc\Downloads\glew-1.13.0")
for make things work. Alternatively(and preferrably), this variable can be set in cache.
Also, given FindGLEW.cmake script uses
$ENV{GLEW_LOCATION}
directory as hint. This means that setting GLEW_LOCATION environment variable will also helps.
CMake cannot locate your GLEW. Thus you have to hint CMake.
Either include GLEW to some place, where CMake looks for components. Installing GLEW comes to mind.
Or you define the variables manually. You already did that for GLEW_INCLUDE_DIR. You have to define GLEW_LIBRARY, too.
It must be the path to the library named glew32, glew, or glew32s. With Unices it should be lib*.so maybe with some additional version numbers. With Windows it should be *.dll or *.lib.

CMake find_package() Eclipse, OS X

I managed to create Make Target in Eclipse and add a CMakeListst.txt to a very simple project and it worked.
Now, my next step is to use two external libraries, Boost and Eigen.
My project is in /Users/MyUser/Documents/workspace/Test
The libraries are /Users/MyUser/Documents/MyLib/Libraries
Now, in the CMakeLists.txt file I try to find Boost and Eigen, which are in the libraries folder, but always the returned message is
CMake Error at CMake/TPLs/FindBoost.cmake:1126 (message): Unable to
find the requested Boost libraries.
Unable to find the Boost header files. Please set BOOST_ROOT to the
root directory containing Boost or BOOST_INCLUDEDIR to the directory
containing Boost's headers. Call Stack (most recent call first):
CMakeLists.txt:23 (FIND_PACKAGE)
-- Configuring incomplete, errors occurred! CMake Error at /Applications/CMake
2.8-11.app/Contents/share/cmake-2.8/Modules/FindPackageHandleStandardArgs.cmake:108
(message): Could NOT find Eigen3 (missing: EIGEN3_INCLUDE_DIRS
EIGEN3_VERSION_OK) (Required is at least version "2.91.0") Call
Stack (most recent call first): /Applications/CMake
2.8-11.app/Contents/share/cmake-2.8/Modules/FindPackageHandleStandardArgs.cmake:315
(_FPHSA_FAILURE_MESSAGE) CMake/TPLs/FindEigen3.cmake:76
(find_package_handle_standard_args) CMakeLists.txt:30 (FIND_PACKAGE)
I am new to CMake, so I must be missing some way to tell CMake to search in my library folder. How can I find the packages with CMake when building the project?
BTW I'm working under Mac OS X Mavericks.
EDIT
Reading through the file FindEigen3.cmake there should be a variable called EIGEN3_INCLUDE_DIRS that points to the include directory of Eigen, is this true?
Now, from the following message
Could NOT find Eigen3 (missing: EIGEN3_INCLUDE_DIRS EIGEN3_VERSION_OK)
I would think that cmake is actually finding that directory as it says EIGEN3_VERSION_OK but then why can't cmake find the rest of the include files?
Am I still missing something? I created the environment variable within Eclipse and then add a line to the FindEigen3.cmake to test the value of the environment variable EIGEN3_INCLUDE_DIRS
message(STATUS "Eigen version: ${EIGEN3_INCLUDE_DIRS}")
But the message I'm getting is
--Eigen version: EIGEN3_INCLUDE_DIRS-NOTFOUND
Any advise?
EDIT
I tried with the question-related answers but none was able to make Eclipse+CMake find Boost and Eigen libraries. I guess the problem here is how to make Eclipse recognize the system variables.
When you do not believe in setting environment variables in Eclipse, you can pass Cmake-defines either directly to cmake command:
cmake -E chdir Release/ cmake -G "Unix Makefiles" ... -DBOOST_ROOT:PATHNAME=boost/install/dir ...
or define them in your CMakeLists.txt before find boost/eigen3
SET(BOOST_ROOT boost/install/dir)
...
FIND_PACKAGE(BOOST ... )
or use environment variables within your OS/shell. You must define them before launching the Eclipse. E.g. from bash, do
export BOOST_ROOT=boost/install/dir
eclipse
Note that you have to define all variables needed for both boost and eigen3. You can place some debugging messages in your CMakeLists.txt to confirm that you pass them correctly:
MESSAGE("Boost root: ${BOOST_ROOT}")