How to add the arguments with each function calling - cmake

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()

Related

cmake: get list of all add_executable names [duplicate]

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()

Using #BASENAME# with install_dir of custom_target() in Meson

#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

How to manually set a CMake path variable to NOTFOUND?

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")

How to use exec statement in a sourced file in Tcl

I am trying to use the following command in a file sourced by another one but the variable doesn't seem to be usefull. The PYTHONPATH var is filled by lib//site-packages and not lib/python2.7/site-packages
my_path:
set pyver [ exec python -c {import sys;print 'python%d.%d'%(sys.version_info[0],sys.version_info[1])} ]enter code here
array set paths {
PATH bin
PYTHONPATH lib/$pyver/site-packages
}
main:
#%Module1.0########################################
##
## Modulefile for texworks
#
source my_path
foreach p [array names paths] {
prepend-path $p $paths($p)
}
If you initialize the array paths like this:
array set paths {
PATH bin
PYTHONPATH lib/$pyver/site-packages
}
the braces around the member initializations prevent variable substitution of the variable pyver. To allow the variable to be substituted, you need to either replace the braces by double quotes (which is somewhat poor style) or write this as
array set paths [list \
PATH bin \
PYTHONPATH lib/$pyver/site-packages \
]
or (setting each member individually)
set paths(PATH) bin
set paths(PYTHONPATH) lib/$pyver/site-packages
or (forcing substitution)
array set paths [subst {
PATH bin
PYTHONPATH lib/$pyver/site-packages
}]
Documentation: array, list, set, subst

How to set default values for Tcl variables?

I have some Tcl scripts that are executed by defining variables in the command-line invocation:
$ tclsh84 -cmd <script>.tcl -DEF<var1>=<value1> -DEF<var2>=<value2>
Is there a way to check if var1 and var2 are NOT defined at the command line and then assign them with a set of default values?
I tried the keywords global, variable, and set, but they all give me this error when I say "if {$<var1>==""}": "can't read <var1>: no such variable"
I'm not familiar with the -def option on tclsh.
However, to check if a variable is set, instead of using 'catch', you can also use 'info exist ':
if { ![info exists blah] } {
set blah default_value
}
Alternatively you can use something like the cmdline package from tcllib. This allows you to set up defaults for binary flags and name/value arguments, and give them descriptions so that a formatted help message can be displayed. For example, if you have a program that requires an input filename, and optionally an output filename and a binary option to compress the output, you might use something like:
package require cmdline
set sUsage "Here you put a description of what your program does"
set sOptions {
{inputfile.arg "" "Input file name - this is required"}
{outputfile.arg "out.txt" "Output file name, if not given, out.txt will be used"}
{compressoutput "0" "Binary flag to indicate whether the output file will be compressed"}
}
array set options [::cmdline::getoptions argv $sOptions $sUsage]
if {$options(inputfile) == ""} {puts "[::cmdline::usage $sOptions $sUsage]";exit}
The .arg suffix indicates this is a name/value pair argument, if that is not listed, it will assume it is a binary flag.
You can catch your command to prevent error from aborting the script.
if { [ catch { set foo $<var1> } ] } {
set <var1> defaultValue
}
(Warning: I didn't check the exact syntax with a TCL interpreter, the above script is just to give the idea).