Reputation: 5591
cmake does not allow you to create multiple targets having the same name at different places in the build tree using add_custom_target(). However, it does provide special targets with that property notably:
Each of these when run within a sub-tree will apply to just that sub-tree. Is there a way achieve the same for user targets?
Here is a simplified example:
toplevel CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
add_custom_target(thing)
add_subdirectory(sub1)
add_subdirectory(sub2)
sub1/CMakeLists.txt:
add_executable(foo foo.cpp)
add_custom_target(thing.sub1 DEPENDS foo)
add_dependencies(thing thing.sub1)
sub2/CMakeLists.txt:
add_executable(bar bar.cpp)
add_custom_target(thing.sub2 DEPENDS bar)
add_dependencies(thing thing.sub2)
I can get almost the behaviour I want in that:
What I would like is to be able to just run make thing and have it apply to the current sub-directory like the all target does.
Is this possible? If not is it a missing feature or would it be a misfeature and if so why?
Solution (almost)
@zuafi's direction led me to a solution.
It is currently possible but only using deprecated behaviour from policy CMP0002. There is effectively a missing feature for adding local targets which is covered by this open ticket.
My workaround is to implement add_local_target() for myself is as follows:
# determine whether local targets should be legal
if("${CMAKE_GENERATOR}" MATCHES "Make")
cmake_policy(SET CMP0002 OLD)
# property seems to be deprecated
set_property(GLOBAL PROPERTY ALLOW_DUPLICATE_CUSTOM_TARGETS 1)
set(ALLOW_LOCAL_TARGETS 1)
message("using Makefile generator")
else()
cmake_policy(SET CMP0002 NEW)
message("Generator=${CMAKE_GENERATOR}")
endif()
# add a custom target with the same name as another (posssibly global) target iff permitted
# see http://stackoverflow.com/questions/35489093/cmake-special-targets-like-all-and-test-having-the-same-name-in-multiple-pl
function(add_local_target target)
if(ALLOW_LOCAL_TARGETS)
set(dependencies "${ARGN}")
foreach(dependency IN LISTS dependencies)
if(TARGET ${dependency})
list(APPEND targets ${dependency})
else()
message("${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt: warning: dependency ${dependency} for add_local_target(${target}) is NOT a target")
endif()
endforeach()
add_custom_target(${target} DEPENDS ${targets})
endif()
endfunction()
This combines well with target paths like target.subdir which can be used as a fall-back if using a non Makefile generator. I just use:
add_local_target(thing DEPENDS thing.sub1)
Update
I think this solution may be subtly broken. If you attempt to build a 'local' target it may build some other 'local' targets as well. However, it will build at minimum what it is supposed to build. It will also build less than a global project wide target with the same name would build. I haven't managed to track this down yet as the makefiles generated by cmake are somewhat gnarly.
Upvotes: 0
Views: 2072
Reputation: 7129
Yes, it is possible... but not with all generators. Particularly it is Ok w/ UNIX Makefiles (see CMP0002 description). And as for me I want to have all unit tests in my project tree to have the same name (I have a bash completion for that name :), so I use the following macro helping me to declare executables:
macro(set_unit_test_target_name OUTPUT_VARIABLE DEFAULT_VALUE)
cmake_policy(GET CMP0002 _may_use_same_name)
if(_may_use_same_name STREQUAL "OLD")
set(${OUTPUT_VARIABLE} "unit_tests")
else()
set(${OUTPUT_VARIABLE} ${DEFAULT_VALUE})
endif()
endmacro()
# usage example
set_unit_test_target_name(UNIT_TESTS someTestExecutable)
add_executable(${UNIT_TESTS} ... )
so for *NIX builds all executables would be named unit_tests
, and have unique names for other generators…
Upvotes: 1