Target visibility for external project

As you might have read in my Topic about using the superbuild pattern as a workspace, I want to emulate some of the functionality that catkin offered for ROS projects.
I would like to structure my projects and my workspace in a way that allows me to relatively easy and in an automated way extract parts of a project into a separate project. That means that I get a lot of cmake code and maybe some targets that are only needed for a single part of the project. Let me give an example:

Imagine you are building something that needs to save … let’s say a struct to disc in binary for some reason. Maybe you decided to use protobuf or capnproto to generate serialization and deserialization routines.
To make your own life easier you encapsulate it in a a small wrapper and make it into a library and teach cmake to run the code generator for protobuf with a custom target and a dependency on your wrapper.

So my current topic is the following:
If you simply use add_subdirectory() the target for protobuf will be present inside your main project and you need to take care that the name does not clash with anything else.
I would like to hide the “Generate me some serializer” target from the outer project, in a way that it will still be executed, but does not clash with the outer project.

I don’t really care, if I need another superbuild pattern, or a lot of ugly code.

Or let me rephrase my problem:
I want to make targets from one CmakeLists.txt available to another, so i can use them. But at the same time, I only want the targets available to the other CMakeLists.txt that I know are useful and safe to use for them.

So is there a way to do this and how do I do it if so.

If I’m understanding things correctly…

One thing you can do is export targets into different EXPORT sets. You can then conditionally include these export set target files based on the COMPONENTS requested of your project. That way the targets only get included if explicitly requested.

As for exporting custom command functionality, I would recommend taking the target name as part of the API that is called so that it is fully controllable by the caller instead of trying to guess some available target name.

Ether I am really blind, or there is not much info about exporting in “The cmake cookbook”. could someone point me to a good guide or example?

2 things:

  1. in the add_subdirectory() call you can use the EXCLUDE_FROM_ALL flag

  2. you just have to take care to choose globally unique target names.

As far as #2 goes, I agree with Other Ben that you should write your API in a way that does this for you. A fairly common pattern I’ve used looks like:

function(add_code_generation)

    set (oneValueArgs NAME TARGET)

    cmake_parse_arguments (ARGS "" "${oneValueArgs}" "" ${ARGN})

    if (NOT ARGS_NAME)
        set (ARGS_NAME "${ARGS_TARGET}_codegen")
    endif()

    add_custom_target ("${ARGS_NAME}" ...)

    add_dependencies ("${ARGS_TARGET}" "${ARGS_NAME}")

endfunction()

Now, you have a flexible API that you can use in two ways:

add_library (myLib STATIC)

# this would create a target named myLib_codegen
add_code_generation (TARGET myLib)

# this would create a target named generate_mylib_code
add_code_generation (TARGET myLib NAME generate_mylib_code)

Thanks alot, that helped me quite a bit, but sadly i hit the next roadblock only one step further…

For things inside a project this is actually fine, but not for the thing I really was thinking about.
I wanted to use nested superbuilds to give me a workspace for me to share targets between projects in the workspace.
Naturally it would be a disaster, if I would dump all my targets into the parent project, since there is no usable way I am aware of that allows to prefix all my targets…
And it would hide tons of footguns that i do not want to expose them to me or my users if it is not necessary.