Is there a way to get all targets of a CMake project from within the top level CMakeLists.txt, i.e. iterate over the targets programmatically?
The reason I want to do this is to apply some XCode specific settings to every target . .
if (CMAKE_GENERATOR MATCHES "Xcode")
include(sanitize_xcode)
sanitize_xcode(myTarget)
endif()
FYI - the sanitization module looks like this . .
macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE)
set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE})
endmacro (set_xcode_property)
macro (sanitize_xcode TARGET)
set_xcode_property(${TARGET} GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Debug] "YES")
set_xcode_property(${TARGET} GCC_GENERATE_DEBUGGING_SYMBOLS[variant=MinSizeRel] "NO")
set_xcode_property(${TARGET} GCC_GENERATE_DEBUGGING_SYMBOLS[variant=RelWithDebInfo] "YES")
set_xcode_property(${TARGET} GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Release] "NO")
set_xcode_property(${TARGET} COPY_PHASE_STRIP[variant=Debug] "NO")
set_xcode_property(${TARGET} COPY_PHASE_STRIP[variant=MinSizeRel] "YES")
set_xcode_property(${TARGET} COPY_PHASE_STRIP[variant=RelWithDebInfo] "NO")
set_xcode_property(${TARGET} COPY_PHASE_STRIP[variant=Release] "YES")
set_xcode_property(${TARGET} GCC_OPTIMIZATION_LEVEL[variant=Debug] "0")
set_xcode_property(${TARGET} GCC_OPTIMIZATION_LEVEL[variant=MinSizeRel] "s")
set_xcode_property(${TARGET} GCC_OPTIMIZATION_LEVEL[variant=RelWithDebInfo] "3")
set_xcode_property(${TARGET} GCC_OPTIMIZATION_LEVEL[variant=Release] "3")
set_xcode_property(${TARGET} IPHONEOS_DEPLOYMENT_TARGET[variant=Debug] "7.0")
set_xcode_property(${TARGET} IPHONEOS_DEPLOYMENT_TARGET[variant=MinSizeRel] "7.0")
set_xcode_property(${TARGET} IPHONEOS_DEPLOYMENT_TARGET[variant=RelWithDebInfo] "7.0")
set_xcode_property(${TARGET} IPHONEOS_DEPLOYMENT_TARGET[variant=Release] "7.0")
endmacro (sanitize_xcode)
In correction to Florian's answer, BUILDSYSTEM_TARGETS is a not really a global property but a directory scoped one. A request for enhancement is currently open to request a truly global property. Using SUBDIRECTORIES property it's possible retrieve recursively all targets in the scope of the current directory with the following function:
function(get_all_targets var)
set(targets)
get_all_targets_recursive(targets ${CMAKE_CURRENT_SOURCE_DIR})
set(${var} ${targets} PARENT_SCOPE)
endfunction()
macro(get_all_targets_recursive targets dir)
get_property(subdirectories DIRECTORY ${dir} PROPERTY SUBDIRECTORIES)
foreach(subdir ${subdirectories})
get_all_targets_recursive(${targets} ${subdir})
endforeach()
get_property(current_targets DIRECTORY ${dir} PROPERTY BUILDSYSTEM_TARGETS)
list(APPEND ${targets} ${current_targets})
endmacro()
get_all_targets(all_targets)
message("All targets: ${all_targets}")
Turning my comment into an answer
To have a list of all targets is a wish that has been out there for a while, but the global property TARGETS is not yet implemented (as for May-2016, see "Listing all targets" discussion).
Edit: It is now implemented: Global BUILDSYSTEM_TARGETS property was released with CMake 3.7
So you can implement this yourself using CMake script itself - as #DevSolar as commented/answered or like here - but I've learned over the time working with CMake that you could also change a lot of target properties globally. E.g. most target properties are defaulted to an equivalent global variable setting.
You can take advantage of this in your case and solve this by adding the following to your global CMakeLists.txt file:
set(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Debug] "YES")
set(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=MinSizeRel] "NO")
set(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=RelWithDebInfo] "YES")
set(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Release] "NO")
set(CMAKE_XCODE_ATTRIBUTE_COPY_PHASE_STRIP[variant=Debug] "NO")
set(CMAKE_XCODE_ATTRIBUTE_COPY_PHASE_STRIP[variant=MinSizeRel] "YES")
set(CMAKE_XCODE_ATTRIBUTE_COPY_PHASE_STRIP[variant=RelWithDebInfo] "NO")
set(CMAKE_XCODE_ATTRIBUTE_COPY_PHASE_STRIP[variant=Release] "YES")
set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL[variant=Debug] "0")
set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL[variant=MinSizeRel] "s")
set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL[variant=RelWithDebInfo] "3")
set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL[variant=Release] "3")
set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET[variant=Debug] "7.0")
set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET[variant=MinSizeRel] "7.0")
set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET[variant=RelWithDebInfo] "7.0")
set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET[variant=Release] "7.0")
References
XCODE_ATTRIBUTE_<an-attribute>
CMAKE_XCODE_ATTRIBUTE_<an-attribute>
If you want to go over a list of targets, set your CMakeLists.txt up to provide that list in the first place.
if ( CMAKE_GENERATOR MATCHES "Xcode" )
include(sanitize_xcode)
endif()
# A list of executables to build
set( project_EXECUTABLES
foo
bar
)
# List of sources for each executable, following some naming scheme
# foo
set( EXE_foo_SOURCES
foo/main.c
)
# bar
set( EXE_bar_SOURCES
bar/main.c
)
# For each executable in the list...
foreach( exe ${project_EXECUTABLES} )
# declare the target...
add_executable( ${exe} ${EXE_${exe}_SOURCES} )
# ...and do whatever additional configuration you need
if ( CMAKE_GENERATOR MATCHES "Xcode" )
sanitize_xcode( ${exe} )
endif()
endforeach()
Related
I am trying here to add the arguments given by the user with every function calling. But currently instead of adding it to the old variable it always overwrites the variable.
In CMakeLists.txt file, when I am calling function mic_set_classes twice. It should append the variable and give the final output as previous call inputs (swsrc pjtsrc) and the new call inputs (pjthdr). But currently the output is only pjthdr.
mic_set_classes(CLASS_TYPE src CLASS_LIST swsrc pjtsrc)
mic_set_classes(CLASS_TYPE hdr CLASS_LIST pjthdr)
for the reference: mic_set_classes function
# argument parsing
set(oneValueArgs CLASS_TYPE)
set(multiValueArgs CLASS_LIST)
cmake_parse_arguments(MIC_SET_CLASSES "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
The final output is the comma separated arguments in this case : pjthdr, . Only this is obtained. Instead of the above, how to print something like this:
swsrc, pjtsrc, pjthdr. All the previous arguments and the current arguments given to the function. Also, I am using:
set_property(GLOBAL PROPERTY GLOBAL_ALL_CLASS ${all_list_types})
and this ${all_list_types}, I am calling in other function using
get_property(class_list GLOBAL PROPERTY GLOBAL_ALL_CLASS).
function(mic_set_classes)
set(oneValueArgs CLASS_TYPE)
set(multiValueArgs CLASS_LIST)
cmake_parse_arguments(MIC_SET_CLASSES "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
# Comma separation
list(LENGTH MIC_SET_CLASSES_CLASS_LIST LENGTH_OF_CLASS_LIST)
MATH(EXPR VAR "${LENGTH_OF_CLASS_LIST}-1")
foreach(Z RANGE 0 ${VAR} )
set(all_list_types "")
foreach(A IN LISTS MIC_SET_CLASSES_CLASS_LIST)
string(APPEND all_list_types "${A},")
endforeach()
endforeach()
set_property(GLOBAL PROPERTY GLOBAL_ALL_CLASS ${all_list_types})
endfunction()
# Function where swsrc, pjtsrc, pjthdr has to be used
function(mic_parse_project)
get_property(class_list GLOBAL PROPERTY GLOBAL_ALL_CLASS)
execute_process(COMMAND ${MIC_PARSE_PROJECT_INVMNG} -c ${class_list})
endfunction()
So, one of my uni courses uses a meson.build system for one of the libraries we have to use.
The library is organized like
this
Now, using CLion, I have trouble linking to that library. Earlier I have been trying cloning it, and setting target_include_directories to the src and includefolders.
For some reason that didn't do the trick, and I'm now trying to convert the meson.build file to a CMakeFiles which I can just add/compile.
The file looks like:
project('animationwindow', ['c', 'cpp'], version: '0.01', default_options: ['cpp_std=c++17', 'default_library=static', 'buildtype=debugoptimized'])
if host_machine.system() == 'windows'
sdl2_dep = subproject('sdl2_windows').get_variable('sdl2_windows_dep')
sdl2image_dep = subproject('sdl2_image_windows').get_variable('sdl2_image_windows_dep')
else
sdl2_dep = dependency('sdl2')
sdl2image_dep = dependency('sdl2_image')
endif
build_files = [
'src/internal/FontCache.cpp',
'src/internal/KeyboardKeyConverter.cpp',
'src/internal/nuklear_implementation.cpp',
'src/widgets/Button.cpp',
'src/widgets/TextInput.cpp',
'src/widgets/DropdownList.cpp',
'src/AnimationWindow.cpp',
'src/Color.cpp',
'src/Image.cpp',
'src/Widget.cpp']
incdir = include_directories('include')
animationwindow = static_library('animationwindow', build_files, include_directories: incdir, dependencies: [sdl2_dep, sdl2image_dep], install: true)
install_subdir('include', install_dir: '.')
install_subdir('src', install_dir: '.')
animationwindow_dep = declare_dependency(link_with: animationwindow, include_directories: incdir)
import('pkgconfig').generate(animationwindow)
# ex = executable('prog', 'src/test.cpp', include_directories: incdir, dependencies: [sdl2_dep, imgui_dep], link_with: animationwindow)
I have converted that to:
cmake_minimum_required(VERSION 3.16)
project(animationwindow)
set(CMAKE_CXX_STANDARD 17)
find_package(SDL2 REQUIRED)
add_executable(
animationwindow
src/internal/FontCache.cpp
src/internal/KeyboardKeyConverter.cpp
src/internal/nuklear_implementation.cpp
src/widgets/TextInput.cpp
src/widgets/Button.cpp
src/widgets/DropdownList.cpp
src/AnimationWindow.cpp
src/Color.cpp
src/Image.cpp
src/Widget.cpp
)
include_directories(animationwindow include)
The question now is, how do I link this from the main file. Can I just somehow link the CMakeLists, or do I have to precomile the library and then somehow add it?
I used the CMake to build an iOS XCode project, I have multiple level source code, so I use 'source_group' to organize them, here is my CMake code
file(GLOB_RECURSE MODULE_DEMO_DIR_FILES
"${MODULE_DEMO_DIR}/*.h"
"${MODULE_DEMO_DIR}/*.m"
"${MODULE_DEMO_DIR}/*.c"
"${MODULE_DEMO_DIR}/*.cc"
"${MODULE_DEMO_DIR}/*.cpp"
"${MODULE_DEMO_DIR}/info.plist"
"${MODULE_DEMO_DIR}/LaunchScreen.storyboard"
"${MODULE_DEMO_DIR}/*.entitlements"
)
foreach(file IN LISTS MODULE_DEMO_DIR_FILES)
message(DEBUG "file:${file}")
get_filename_component(fileDirectory ${file} DIRECTORY)
include_directories(${fileDirectory})
endforeach()
set(${MODULE_DEMO_SOURCES} ${MODULE_DEMO_DIR_FILES} PARENT_SCOPE)
source_group(TREE ${MODULE_DEMO_DIR} FILES ${MODULE_DEMO_DIR_FILES})
when I select any directory and right-click and select 'show in Finder', it does not jump right directory, in the xcodeproj file, I find the directory PBXGroup is this:
8CD0C75957674E25982ACF10 /* IQTextView */ = {
isa = PBXGroup;
children = (
8D7EEDCDA3CC4AA6A444A78F /* /Users/lee/Desktop/xx1/demo/company/xx2/xx3/demo/Vendor/IQKeyboardManager/IQTextView/IQTextView.h */,
F54B85341C9A4BC7BD92320D /* /Users/lee/Desktop/xx1/demo/company/xx2/xx3/demo/Vendor/IQKeyboardManager/IQTextView/IQTextView.m */,
);
name = IQTextView;
sourceTree = "<group>";
};
when I change the "name = IQTextView;" to "path = IQTextView;",it works!
my question is:
how let the PBXGroup use 'path' instead of 'name' when using CMake, so that I can jump to the true path when clicking "show in Finder" at a directory in XCode project?
#BASENAME# does not appear to work in the install_dir: parameter of the Meson custom_target() function.
protoc = find_program('protoc')
protobuf_sources= [
'apples.proto',
'oranges.proto',
'pears.proto'
]
protobuf_generated_go = []
foreach protobuf_definition : protobuf_sources
protobuf_generated_go += custom_target('go_' + protobuf_definition,
command: [protoc, '--proto_path=#CURRENT_SOURCE_DIR#', '--go_out=paths=source_relative:#OUTDIR#', '#INPUT#'],
input: protobuf_definition,
output: '#BASENAME#.pb.go',
install: true,
install_dir: 'share/gocode/src/github.com/foo/bar/protobuf/go/#BASENAME#/'
)
endforeach
I need the generated files to end up in at directory based on the basename of the input file:
share/gocode/src/github.com/foo/bar/protobuf/go/apples/apples.pb.go
share/gocode/src/github.com/foo/bar/protobuf/go/oranges/oranges.pb.go
share/gocode/src/github.com/foo/bar/protobuf/go/pears/pears.pb.go
If I use #BASENAME# in install_dir: to try and create the directory needed, it does not expand, and instead just creates a literal '#BASENAME#' directory.
share/gocode/src/github.com/foo/bar/protobuf/go/#BASENAME#/apples.pb.go
share/gocode/src/github.com/foo/bar/protobuf/go/#BASENAME#/oranges.pb.go
share/gocode/src/github.com/foo/bar/protobuf/go/#BASENAME#/pears.pb.go
How can the required installed directory location based on the basename be achieved?
(just 3 files in the above example, I actually have 30+ files)
Yes, it looks as there is no support for placeholders like BASENAME for install_dir parameter since this feature aims at file names not directories. But you can process iterator that is string in a loop:
foreach protobuf_definition : protobuf_sources
...
install_dir: '.../go/#0#'.format(protobuf_definition.split('.')[0])
endforeach
I'm hardcoding a library path before hand and want to set the path to NOTFOUND manually if the file doesn't exist.
set(MY_LIB "path that doesn't exist")
if(NOT EXISTS "${MY_LIB}")
message("not found")
// set it back to NOTFOUND ??
endif()
if (MY_LIB)
// set flags
endif()
How to manually set a CMake path variable to NOTFOUND?
Just set it to the string:
set(MY_LIB "NOTFOUND")