Trying out CMake presets, falling at one of the very first hurdles.
I have this simple "CMakePresets.json" alongside my CMakeLists.txt
{
"version": 2,
"configurePresets": [
{
"name": "simple",
"displayName": "simple"
}
],
"buildPresets": [
{
"name": "dev",
"configurePreset": "simple"
}
]
}
This is my very simple CMakeLists.txt
cmake_minimum_required(VERSION 3.21.1)
project(hello)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# I want these supplied by the presets
# with QTDIR in the user specific presets
# as these will differ from dev person to
# dev person
# ------------------------------------
# set(CMAKE_AUTOMOC ON)
# set(CMAKE_AUTOUIC ON)
# set(CMAKE_CXX_STANDARD 17)
# set(CMAKE_CXX_STANDARD_REQUIRED ON)
# set(CMAKE_PREFIX_PATH $ENV{QTDIR})
find_package(Qt6 REQUIRED COMPONENTS Quick)
qt_add_executable(${PROJECT_NAME}
main.cpp
)
target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Quick)
qt_add_qml_module(${PROJECT_NAME}
URI qml
VERSION 1.0
QML_FILES main.qml)
I then (on a clean setup) run
mkdir build
cd build
cmake .. --preset=dev
But I always get the following error
CMake Error: Could not read presets from
/home/.../cmake/simple: Invalid preset
I get the same message if I try
cmake .. --list-presets
I either must be invoking cmake incorrectly, or there is something wrong with my JSON.
Can someone point out my mistake?
For instance:
Does the preset name from the CMakePresets.json need to match the project name in the CMakeLists.txt?
Keeping in mind that a CMakeLists.txt can build multiple targets.
Before version 3 a configure preset requires to have fields generator and binaryDir. From the documentation:
generator
An optional string representing the generator to use for the preset.
If generator is not specified, it must be inherited from the inherits preset (unless this preset is hidden).
In version 3 or above, this field may be omitted to fall back to regular generator discovery procedure.
binaryDir
An optional string representing the path to the output binary directory.
This field supports macro expansion. If a relative path is specified, it is calculated relative to the source directory.
If binaryDir is not specified, it must be inherited from the inherits preset (unless this preset is hidden).
In version 3 or above, this field may be omitted.
See also https://discourse.cmake.org/t/cmake-invalid-preset/3538.
Related
I'm trying to link a fortran project against jsonfortran. Below is a mwe which fails because the module file cannot be found. This happens when the include path is not properly set.
main.F90
program thing_program
use json_module, only : json_ck
implicit none
character(kind=json_ck, len=:), allocatable :: json_string
json_string = "{}"
write(*, *) json_string
end program thing_program
CMakeLists.txt
cmake_minimum_required(VERSION 3.21)
project(
myproj
VERSION 0.0.0
LANGUAGES Fortran
)
# don't build json-fortran docs
set(SKIP_DOC_GEN ON CACHE INTERNAL "")
#json fortran uses the compiler id as an identifier
string(TOLOWER ${CMAKE_Fortran_COMPILER_ID} compiler_id)
include(FetchContent)
FetchContent_Declare(jsonfortran-${compiler_id}
GIT_REPOSITORY https://github.com/jacobwilliams/json-fortran.git
GIT_TAG 3ab8f98209871875325c6985dd0e50085d1c82c2 # 8.3.0
# if the project is installed system-wide, use that instead of building it ourselves
FIND_PACKAGE_ARGS NAMES jsonfortran-${compiler_id}
)
FetchContent_MakeAvailable(jsonfortran-${compiler_id})
add_executable( thing main.F90 )
target_link_libraries(thing
PUBLIC
jsonfortran-${compiler_id}
)
Before using FetchContent, I was able to add jsonfortran with find_package, but I had to use target_link_libraries(thing PUBLIC jsonfortran-${compiler_id}::jsonfortran) to get cmake to generate properly. After using FetchContent, that same call to target_link_libraries fails, but works if I change it to this target_link_libraries(thing PUBLIC jsonfortran-${compiler_id}).
I'm guessing that the includes directory isn't being properly set so the fortran mod files cannot be found because the call to target_link_libraries is somehow incorrect, but I am not sure how to make it function properly. Any idea what's going on?
The actual error, if you're interested:
[ 6%] Building Fortran object CMakeFiles/thing.dir/main.F90.o
/Users/kshores/Downloads/thing/main.F90:2:7:
2 | use json_module, only : json_ck
| 1
Fatal Error: Cannot open module file 'json_module.mod' for reading at (1): No such file or directory
compilation terminated.
Update: The mod files are created and placed into _deps/jsonfortran-gnu-build when they should be placed into _deps/jsonfortran-gnu-build/include. With make VERBOSE=1, I see that in fact the include directory is added -I/Users/kshores/Downloads/thing/build/_deps/jsonfortran-gnu-build/include, but the mod files are not there for some reason.
I want to use
Visual Studio 2022
CMakeLists.txt based project
LLVM and C++
To be able to have for future multiple Clang Versions in parallel on my HardDrive (e.g. Support of older projects), I do not want to add Clang to my system path.
If I run that setup in the command line it works without having to add CLANG to my system path. But it does not in Visual Studio
The current setup for Visual Studio works with a batch file adding the Clang Path to the current System Path and starting Visual Studio afterward.
Here is my current CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
set(PROJECT_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../../..")
set(CMAKE_PREFIX_PATH "${PROJECT_ROOT}/tools/compiler/LLVM/bin")
# Check if the compiler is available in the expected directory
find_path(COMPILER_DIR
NAMES clang.exe
)
# Check if the compiler was found
IF( IS_DIRECTORY "${COMPILER_DIR}")
# We want to choose the compiler used for this project
# This works only if the set is done before the project() call
set(CMAKE_C_COMPILER ${COMPILER_DIR}/clang.exe CACHE PATH "" FORCE)
set(CMAKE_CXX_COMPILER ${COMPILER_DIR}/clang++.exe CACHE PATH "" FORCE)
ELSE()
MESSAGE(STATUS "Compiler directory not found")
ENDIF()
project(runUnitTests)
# removed some lines ...
set(GTEST "${PROJECT_ROOT}/tools/googletest-main")
set(COMMON "${PROJECT_ROOT}/common")
# ----======================================================================----
add_definitions(-DINLINE=inline)
add_definitions(-DUNIT_TEST)
add_definitions(-DGTEST_USE_OWN_TR1_TUPLE)
# Prevent overriding the parent project's compiler/linker
# settings on Windows
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# ----======================================================================----
# GTest.
# ----======================================================================----
# enable CMake’s test runner to discover the tests included in the binary,
# using the GoogleTest CMake module.
include(GoogleTest)
# add the google test directory as a subdirectory
# by this it gets automatically build and the libraries are put into the "out" directory
add_subdirectory(${GTEST} out)
# Add include directories
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${GTEST}/googletest/include
${GTEST}/googlemock/include
# removed some lines ...
)
# ----======================================================================----
# Headers.
# ----======================================================================----
file(GLOB_RECURSE ${PROJECT_NAME}_HEADERS "*.h" "*.hpp")
# ----======================================================================----
# Sources.
# ----======================================================================----
# Main Sources
set(SOURCES
# removed some lines ...
./main_pc.cpp
)
# additional source files
set(ADDITIONAL_SOURCES
# Please add here the source files needed for your test
./sampleClass.cpp
)
# Test case source files
set(TEST_SOURCES
# Please add here your own test case files
./test_sampleClass.cpp
)
# ----======================================================================----
# Executable setup
# ----======================================================================----
# Test without matlab libraries
add_executable(${PROJECT_NAME} ${SOURCES} ${ADDITIONAL_SOURCES} ${TEST_SOURCES} ${${PROJECT_NAME}_HEADERS})
# add the gtest/gmock library to the linker
target_link_libraries(${PROJECT_NAME} gtest gmock)
# This is so you can do 'make test' to see all your tests run, instead of
# manually running the executable runUnitTests to see those specific tests.
add_test(NAME allTests COMMAND runUnitTests)
# Check if the teamcity envoirnment variable is set
# Because when running on teamcity the gtest_discover_tests call fails
# But this is needed that the Visual Studio Test Explorer can detect the test cases.
if(NOT DEFINED ENV{TEAMCITY_VERSION})
enable_testing()
# since CMake 3.10 it is possible to scan the test executable for test
# This is needed that Visual Studio Test Explorer is able to display the test cases
gtest_discover_tests(${PROJECT_NAME})
endif(NOT DEFINED ENV{TEAMCITY_VERSION})
and here is my CMakeSettings.json
{
"configurations": [
{
"name": "x86-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "clang_cl_x86" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": ""
}
]
}
Error message in Visual Studio if Clang is not in Path:
1> CMakeSettings Error at CMakeSettings.json: Failed to load configuration 'x86-Debug'. Enable Cross Platform Logging for more information.
1> Failed to load configuration 'x86-Debug'. Enable Cross Platform Logging for more information.
1> Failed to load configuration 'x86-Debug'. Enable Cross Platform Logging for more information.
I enabled "Cross Platform Logging" but it is empty.
Tried also to set absolute paths in CMakeLists to CLANG. Did not change the situation.
When I run Visual Studio once with CLang in the Path and compile the project -> it works on the next start for Visual Studio that Clang is NOT in the PATH. When I delete the "out" folder, back to failing.
I am trying to make a cross-platform CMake for my project (Windows and Linux).
I need to use external libraries (yaml-cpp). On Linux, I just had to do an apt get and use find_package. But on Windows, I need to append the CMAKE_MODULE_PATH in order for my program to find the yaml-cpp-config.cmake.
So I start by installing yaml-cpp (https://github.com/jbeder/yaml-cpp) with CMake GUI 3.16 and mingw32 (mingw32-make install).
I have tried the library on a hello world project, and it works fine.
cmake_minimum_required(VERSION 3.1)
project (yaml_test)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
message (STATUS "Yaml-cpp include = $ENV{YAML_CPP_INCLUDE_DIR}")
message (STATUS "Yaml-cpp library = $ENV{YAML_CPP_LIBRARIES}")
include_directories ($ENV{YAML_CPP_INCLUDE_DIR})
add_executable(yaml_test main.cpp)
target_link_libraries(yaml_test $ENV{YAML_CPP_LIBRARIES})
But now, I want to include the library in my project and use find_package. But the yaml-cpp-config.cmake looks like this:
# - Config file for the yaml-cpp package
# It defines the following variables
# YAML_CPP_INCLUDE_DIR - include directory
# YAML_CPP_LIBRARIES - libraries to link against
# Compute paths
get_filename_component(YAML_CPP_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
set(YAML_CPP_INCLUDE_DIR "")
# Our library dependencies (contains definitions for IMPORTED targets)
include("${YAML_CPP_CMAKE_DIR}/yaml-cpp-targets.cmake")
# These are IMPORTED targets created by yaml-cpp-targets.cmake
set(YAML_CPP_LIBRARIES "")
The YAML_CPP_INCLUDE_DIR and YAML_CPP_LIBRARIES variables are empty, and even if CMake found yaml-cpp-config.cmake, It doesn't work. So what do I have missing in the installation of yaml-cpp? Should I have set the paths by hand?
The absence of definition of YAML_CPP_INCLUDE_DIR and YAML_CPP_LIBRARIES variables is the issue with the yaml-cpp project which is already reported here.
Instead of variables described in this config file, use target yaml-cpp:
add_executable(yaml_test main.cpp)
# This provides both include directories and libraries.
target_link_libraries(yaml_test yaml-cpp)
Linking with an IMPORTED target (yaml-cpp in this case) is known as CMake "modern way".
My CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
project (foo)
include(FeatureSummary)
find_package(OpenSSL REQUIRED)
find_package(PkgConfig QUIET)
pkg_check_modules(JSON REQUIRED json-c)
feature_summary(WHAT ALL)
Running cmake . gives me:
-- The following REQUIRED packages have been found:
* OpenSSL
Can anyone explain the trick to make FeatureSummary also include packages found by pkg_check_modules?
UPDATE
If I create a file named FindJSON.cmake with the following code:
find_package(PkgConfig QUIET)
# --> Still using pkg_check_modules
pkg_check_modules(JSON REQUIRED QUIET json-c)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
JSON
DEFAULT_MSG
JSON_LIBRARIES
JSON_INCLUDE_DIRS)
and change CMakeLists.txt to:
cmake_minimum_required(VERSION 2.8)
project (foo)
include(FeatureSummary)
find_package(OpenSSL REQUIRED)
set(CMAKE_MODULE_PATH . ${CMAKE_MODULE_PATH})
# --> Now using find_package which still uses pkg_check_modules
find_package(JSON REQUIRED)
feature_summary(WHAT ALL)
I get:
-- The following REQUIRED packages have been found:
* OpenSSL
* JSON
That is fine. What has changed?
I use find_package_handle_standard_args. Alright let me just copy the content of FindJSON.cmake to CMakeLists.txt, instead of using it through find_package.
The new CMakeLists.txt will look like this:
cmake_minimum_required(VERSION 2.8)
project (foo)
include(FeatureSummary)
find_package(OpenSSL REQUIRED)
# --> The code from from FindJSON.cmake
find_package(PkgConfig QUIET)
# --> Still using pkg_check_modules
pkg_check_modules(JSON REQUIRED QUIET json-c)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
JSON
DEFAULT_MSG
JSON_LIBRARIES
JSON_INCLUDE_DIRS)
# <-- end of code from FindJSON.cmake
feature_summary(WHAT ALL)
and the output:
-- The following REQUIRED packages have been found:
* OpenSSL
JSON has disappeared again.
So find_package does some magic of which I am unaware.
There is magic happening inside find_package. It's storing the names of packages into global properties.
You can mess with those properties yourself:
set_property(GLOBAL APPEND PROPERTY PACKAGES_FOUND MyJunkPackage)
Check the source of FeatureSummary.cmake to see which other properties and variables it refers to in order to produce. For example, to make this package show up in the "required" list,
set_property(GLOBAL APPEND PROPERTY _CMAKE_MyJunkPackage_TYPE REQUIRED)
Use find_package_handle_standard_args and pass the according variables from find_package.
pkg_check_modules(FOO)
find_package_handle_standard_args(FOO
DEFAULT_MSG
FOO_FOUND
)
In your case replace FOO by SQLITE3.
Documentation:
https://cmake.org/cmake/help/v3.6/module/FindPackageHandleStandardArgs.html
Alternatively, to add a custom entry to the feature summary use add_feature_info.
The documentation states:
add_feature_info(<name> <enabled> <description>)
Use this macro to add
information about a feature with the given <name>. <enabled> contains
whether this feature is enabled or not, <description> is a text
describing the feature.[..]
Example for setting the info for a feature:
option(WITH_FOO "Help for foo" ON)
add_feature_info(Foo WITH_FOO "The Foo feature provides very cool stuff.")
https://cmake.org/cmake/help/v3.6/module/FeatureSummary.html
I am struggling to make a CMakeList.txt file to reflect a simple, typical makefile. The original is here http://pastebin.com/S9Czr1pt .
I tried many things (like SET(SOURCE ... and SET(HEADERS... ) to add /src, /lib and /third-party//include ), but I have no luck.
Can anyone either help me out or point to a tutorial that does this thing?
This is just an out of the blue skeleton - please see the CMake documentation for details of each function:
cmake_minimum_required(VERSION 2.6)
# Project name, can be used as target name too
project(Example)
# Search all .cpp files within src - recursive!
# You can add all source files by hand here too
file(GLOB_RECURSE SRCS "src/*.cpp")
# Add include path (you can also add it's sub directories
include_directories("include")
# Search for packages -- PLEASE NOTE: many libraries provide alternative's to this
# which often provide more functionality
find_package(PkgConfig REQUIRED)
# TODO: add proper pkg modul search info's and change the variable's name
pkg_search_module(PACKAGE_NO1 ...)
# Show some messages (optional)
if( (PACKAGE_NO1 )
include_directories(${(PACKAGE_NO1_INCLUDE_DIRS})
message(STATUS "Using OpenSSL ${(PACKAGE_NO1_VERSION}")
else()
# do error handling
endif()
# Add compiler flags
add_definitions(-std=c++11 -Wall) # -g O3 etc are added according to Release / Debug compilation
# Build a executable target (1st param: Target name; 2nd: source files)
add_executable(${PROJECT_NAME} ${SRCS})