multiple inner @ variable in config

I am currently writing this line on my Config.cmake.in

set_and_check(@MYVAR@ "@PACKAGE_@PROJECT_NAME@@")

I would like both my variable to be interpreted but @PROJECT_NAME@ is not

I know there is a way to do it but i do not know how

Do you guys have some ideas ?

Thx in advance :slight_smile:

Does this do what you want:

set(project_name "@PROJECT_NAME@")
set_and_check(@MYVAR@ "@PACKAGE_${project_name}@")

If this is going to be in a package’s config file, make sure you unset any temporary variables so they don’t leak into the calling scope. You should also name any temporary variables with names that are specific to your package so they don’t clash with any variables in the consuming project.

It seems, it does not work as i want to, i share you some piece of code

Here is my CMakeLists

project(A)

set(${PROJECT_NAME}_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include")
set(${PROJECT_NAME}_LIBRARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib")

configure_package_config_file(${CMAKELIB_DIRECTORY}/resources/template/Config.cmake.in
    "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake"
    INSTALL_DESTINATION cmake
    PATH_VARS ${PROJECT_NAME}_INCLUDE_DIR ${PROJECT_NAME}_LIBRARY_DIR
)

Here is my Config.cmake.in

set(current_project_name "@PROJECT_NAME@")

set(@PROJECT_NAME@_INCLUDE_DIR "@PACKAGE_${current_project_name}_INCLUDE_DIR@")
set(@PROJECT_NAME@_LIBRARY_DIR "@PACKAGE_@PROJECT_NAME@_LIBRARY_DIR@")
set(@PROJECT_NAME@_INCLUDE_DIR2 "@PACKAGE_A_INCLUDE_DIR@")

And here is the output

set(ChangelogGenerator_INCLUDE_DIR @PACKAGE_${current_project_name}_INCLUDE_DIR@) #incorrect
set(A_LIBRARY_DIR PROJECT_NAME) #incorrect
set(A_INCLUDE_DIR2 "C:/Users/xxxx/Desktop/Coding/cmakeLib/include") #correct (do not care about absolute path this is for the example)

Maybe i did something wrong with your code ?

Sorry, I was in a rush when I replied yesterday. My suggestion was nonsense.

For the specific example you gave, don’t try to overuse PROJECT_NAME. In fact, I would suggest you should not have used it at all anywhere in your example code. The reality is that you should not really ever change the project name once the project is more than just a quick prototype that only one person uses. As soon as others might be using your project as a dependency, the project name should stay the same because consumers may rely on it.

Another reason is that many people confuse the concept of “project” and “target”. They are two different things, but it is a common mistake that people use ${PROJECT_NAME} throughout their code in places where a target name is expected. This makes the code confusing to read. Even for projects having just one main target, you gain nothing by putting ${PROJECT_NAME} instead of the actual target name directly. Either way, you’re copying around a string that has to be identical in all places. You may as well put the actual target name there to improve readability.

Interestingly, your original problem is another case of using ${PROJECT_NAME} in places where something else is expected. While the majority of projects do use the same name for the project name and their package name (and that’s usually a sensible thing to do), it also isn’t required to be that way. And the same argument applies as for targets - once you have consumers of your package, you shouldn’t change the package name because consumers will depend on it not changing. So once again, you can and should just hard-code the package name in places where you need to use it.

If you follow the above advice, your original problem goes away. Your code line would reduce to (if the package name is A):

set_and_check(@MYVAR@ "@PACKAGE_A@")

Now it also becomes clear that this probably doesn’t make sense either. Why prefix A with PACKAGE_...? That would only be needed for something that evaluates to a path of something in your install area. Your expanded example in your latest reply makes a bit more sense, and it reduces down to something much clearer when you get rid of all the ${PROJECT_NAME} uses:

set(A_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include")
set(A_LIBRARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib")

configure_package_config_file(${CMAKELIB_DIRECTORY}/resources/template/Config.cmake.in
    "${CMAKE_CURRENT_BINARY_DIR}/AConfig.cmake"
    INSTALL_DESTINATION cmake
    PATH_VARS A_INCLUDE_DIR A_LIBRARY_DIR
)

Hey @craig.scott

Thanks for answering

I agree with you, when you say that people should not use PROJECT_NAME on their code to refer to their target.

In fact i am using a variable name TARGET_NAME.

The problem is that i have a lot of CMakeLists (all of them use the variable TARGET_NAME) and i wanted to use a template for my Config.cmake.in

As a result i would like to use

set(@TARGET_NAME@_INCLUDE_DIR "@PACKAGE_@TARGET_NAME@_INCLUDE_DIR@")

As you noticed before, the problem is that my variable @TARGET_NAME@ is not interpreted on
@PACKAGE_@TARGET_NAME@_INCLUDE_DIR@.

Should i really write a new Config.cmake.in for each of my projects ?

How about configuring that file twice, once for @@ style with @ONLY and once for ${} style.

However, I think you did not make your use case clear. It looks like an unusual approach that may be usually solved completely different. Maybe, you can show us what you actually want to achieve?

Hey @hsattler !

I just want to write a Config file that allow my consumer to access some variable define in that package.

I mean for example, access the include dir, the lib dir, define some preprocessor, etc

The usual way is to directly give the name of the target on the config variable, but i really prefer use a variable for maintanabilty.

This is why i’m using set(@TARGET_NAME@_INCLUDE_DIR "@PACKAGE_@TARGET_NAME@_INCLUDE_DIR@")

The problem with

is that it is not well-defined. You could also have @PACKAGE_@ and @_INCLUDE_DIR@ as replacements. I already mentioned the two-stage approach. This also solves the ambiguity.

Hey,

I changed my mind and i will try to use a set_target_properties() on my target and the consumer will retreive it using a get_target_property()

I think the is the best way to give variable from a target to another.

Thanks for your support !