0

I am generating Visual Studio files with CMake for C++. I have project A and project B that depend on a self-made library.

main_folder
 CMakeLists.txt
  |- build
  |_ Libfolder
  |   CMakeLists.txt
  |_ Proj_A_folder
  |   CMakeLists.txt
  |_ Proj_B_folder
      CMakeLists.txt

I am adding all of them as subdirectories (and they should be since I am also still working on the said library). However, running cmake .. from the build directory the first time generates:

CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
LIB
    linked by target "Proj_A" in directory C:/CodeAmber/main_folder/Proj_A_folder
    linked by target "Proj_B" in directory C:/CodeAmber/main_folder/Proj_B_folder

The .sln file has generated, and I can then open it, build Mylib, and run cmake .. again, and it works. However, that behaviour is not nice of course. I want it to see the dependency correctly and always build the Mylib first (preferably also on the compilation of proj_A and B automatically).

If I build the Mylib by hand, and then execute cmake .., the CMake call then completes successfully but does not actually build the project A and B themselves to .exe. That is also something I do not understand, how to trigger this?

I have searched a lot for answers, but most have a very different project folder structure or use External_Project (I'm still working on the library, so this is not useful). The answers I did find say that just target_link_libraries is enough to create a dependency. However, I think if find_library does not find anything in the first place, that causes the problem. However, I have not been able to find a solution, and I also do not understand why other than the visual studio files, it does not actually build my executable.

Also, I am relatively new to CMake, so it would be wonderful if you could give an example how to call a command you suggest.

main_folder

# Solution
project(VRshoes_PC_side)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)

# Split in projects of our own software (defining folder names)
set(LIB Libfolder)
set(PROJ_A Proj_A_folder)
set(PROJ_B Proj_B_folder)

add_subdirectory(${LIB})
add_subdirectory(${PROJ_A})
add_subdirectory(${PROJ_B })

Libfolder

cmake_minimum_required (VERSION 3.8)

set(THIS_LIB Mylib)


file(GLOB_RECURSE HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h")
file(GLOB_RECURSE SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")


set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/build/) # .dll
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/build/) # .lib
set(CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/build/) # .pdb

# Only put SHARED if you ONLY want a DLL. That was my mistake earlier, we need a LIB file too.
add_library(${THIS_LIB} "${HEADERS}" "${SOURCES}")

add_custom_target(alwaysbuild ALL)

target_include_directories(${THIS_LIB} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${CMAKE_CURRENT_SOURCE_DIR}/libraries/include/)

target_link_libraries(${THIS_LIB} PUBLIC  setupapi wsock32 ws2_32 bthprops)

source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/include" PREFIX "Header Files" FILES ${HEADERS})
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/src" PREFIX "Source Files" FILES ${SOURCES})

target_sources(${THIS_LIB} INTERFACE
    ${CMAKE_CURRENT_SOURCE_DIR}/*.h
    ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
)

Proj_A_folder

cmake_minimum_required (VERSION 3.8)

# If you disable this, it expects WinMain instead of main as application entry point.
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:CONSOLE /ENTRY:mainCRTStartup")


set(THIS_PROJECT_NAME PROJ_A)

set(LIB_DIR ${PROJECT_SOURCE_DIR}/Libfolder)

# Linking to self made libraries in a project: https://stackoverflow.com/questions/11216408/cmake-dependencies-headers-between-apps-libraries-in-same-project

find_library(LIB NAMES Mylib PATHS ${LIB_DIR}/build/Debug NO_DEFAULT_PATH )

add_executable (${THIS_PROJECT_NAME} WIN32 "main.cpp" "main.h")


target_link_libraries(${THIS_PROJECT_NAME} ${LIB})
target_include_directories(${THIS_PROJECT_NAME} PUBLIC ${LIB_DIR}/include)

EDIT: Based on Tsyvarevs comments, I changed the target_link_libraries to the following, so I now have:

target_include_directories(${THIS_PROJECT_NAME} PUBLIC ${LIB_DIR}/include) 
target_link_libraries(${THIS_PROJECT_NAME} PUBLIC Mylib)

This gives an error on running cmake ..:

CMake Error at Proj_A/CMakeLists.txt:15 (add_executable):

Cannot find source file:

    C:/CodeAmber/pc_side_cpp/Lib_folder/*.h

  Tried extensions .c .C .c++ .cc .cpp .cxx .cu .mpp .m .M .mm .ixx .cppm .h
  .hh .h++ .hm .hpp .hxx .in .txx .f .F .for .f77 .f90 .f95 .f03 .hip .ispc

Proj_B_folder

# long thing probably requires the same solution.
# just to indicate I don't want to solve it by having my Proj_A in the main folder so I only have two CMakeLists.txt.
Amber Elferink
  • 132
  • 1
  • 10
  • "The answers I did find say that just `target_link_libraries` is enough to create a dependency." - These answers are correct ones. Have you tried them? "However, I think if `find_library` does not find anything in the first place, that causes the problem." - No, this is wrong assumption, failing `find_library` doesn't mean failing `target_link_libraries`. – Tsyvarev Mar 21 '22 at 01:01
  • @Tsyvarev, I have `target_link_libraries(${THIS_PROJECT_NAME} ${LIB})` in Proj_A (and similar in Proj_B). Is that not enough? I have also tried to put this in the main_folder with `target_link_libraries(${PROJ_A} ${LIB})` but that gives an error. I think it does not understand me using the folder names, but am not sure how to do it otherwise since I don't have access to subdirectory variables (other than hardcoding it). – Amber Elferink Mar 21 '22 at 01:04
  • The libraries created in the CMake project itself could be linked to using their **target names**: `target_link_libraries(PROJ_A Mylib)`. See e.g. that question: https://stackoverflow.com/questions/56210202/how-to-link-static-library-that-was-created-from-add-subdirectory-in-cmake – Tsyvarev Mar 21 '22 at 07:28
  • The variables in the target_link_libraries of Proj_A and Proj_B are already equal to that. So you do mean it should linked be in main_folder as well? If I do that I get errors: – Amber Elferink Mar 21 '22 at 10:38
  • ``` CMake Error at CMakeLists.txt:35 (target_link_libraries): Attempt to add link library "Mylib" to target "PROJ_A" which is not built in this directory. This is allowed only when policy CMP0079 is set to NEW. CMake Error at CMakeLists.txt:36 (target_link_libraries): The keyword signature for target_link_libraries has already been used with the target "PROJ_B". All uses of target_link_libraries with a target must be either all-keyword or all-plain. The uses of the keyword signature are here: * Proj_B_folder/CMakeLists.txt:45 (target_link_libraries) ``` – Amber Elferink Mar 21 '22 at 10:38
  • "The variables in the target_link_libraries of Proj_A already equal to that." - Yes, the executable is specified in the same manner as in your code. The key point is how the **library** is specified: via name, not via path. "So you do mean it should linked be in main_folder as well?" - No, I didn't mean that. You could remain `target_link_libraries` call in the same place as you currently have it. As for keyword (`PRIVATE` or `PUBLIC`) it is up to you whether to use it in the `target_link_libraries` call. Just make sure you use keywords consistently (as the second error message tells you). – Tsyvarev Mar 21 '22 at 10:52
  • I just tried to hardcode it, and this is weird: So I have the lines ``` target_include_directories(${THIS_PROJECT_NAME} PUBLIC ${LIB_DIR}/include) target_link_libraries(${THIS_PROJECT_NAME} PUBLIC Mylib) ``` (I only changed the target_link_libraries part to match what you said.) Then it suddenly cannot find my include files anymore, while normally it could. ``` Cannot find source file: C:/CodeAmber/pc_side_cpp/Lib_folder/*.h ``` It is not searching in the include folder anymore, while I haven't changed that! – Amber Elferink Mar 21 '22 at 11:03
  • "Then it suddenly cannot find my include files anymore" - Which files are not found? Do they belong to the library or to the executable? What is compiled when you see the error, the library or the executable? Where header files are actually located (you don't show them in your project's layout)? Please, **update the question post** with your new attempt and the error message is causes. Note, that on Stack Overflow the question post should contain all relevant information. Comments are only for request that information. – Tsyvarev Mar 21 '22 at 11:10
  • In CMake star symbol (`*`) has no special meaning. For collect all sources/headers in a directory use `file(GLOB)` command, as in that question: https://stackoverflow.com/questions/3201154/automatically-add-all-files-in-a-folder-to-a-target-using-cmake – Tsyvarev Mar 21 '22 at 12:58
  • BTW, a call to `target_sources` with INTERFACE keyword rarely has a sense. Why do you use it? You have already specify sources for the library when call `add_library`. – Tsyvarev Mar 21 '22 at 13:08

0 Answers0