There are numerous similar questions on Stack Overflow, but none come near to answering my question.
I have a C++ library built using CMake:
mylib
| - CMakeLists.txt
| - src/
| | - m.h
| | - m.cpp
| - include/
| | - mylib/
| | | - a.h
| | | - something/
| | | | - some.h
| - cmake/
| - mylibConfig.cmake.in
| - mylibConfigVersion.cmake.in
I then create another library or executable which includes the aforementioned library:
myapp
| - CMakeLists.txt
| - src/
| | - main.cpp
| - include/
| | - myapp/
| | | - b.h
| - libs
| | - mylib
And would like to use mylib within myapp like so. Please take notice how mylib headers are included in a directory like format:
#include <mylib/a.h>
#include <mylib/something/some.h>
mylib should be built when building myapp so that the following works without any other build steps:
$ cd myapp/build
$ cmake ..
$ make
Here is a list of some of the Stack Overflow posts I have reviewed. I have attempted each, and they simply do not work:
CMake: How to build external projects and include their targets
CMake ExternalProject_Add() and FindPackage()
Assuming in the project described, only header files in the mylib/include directory are to be considered public:
The top-level CMakeLists.txt for mylib needs to contain:
cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
project(mylib VERSION 0.1 LANGUAGES CXX)
add_library(${MyLibName} ${MyLib_SOURCES})
target_include_directories(${MyLibName}
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
)
This ensures that projects including mylib will only have access to files in the include/ directory. Files in include/ can be used like #include <myfile.h> and files in include/mylib (the general convention) can be used like #include <mylib/myfile.h>.
The top-level CMakeLists.txt for myapp should include:
cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
project(myapp VERSION 0.1 LANGUAGES CXX)
add_subdirectory(libs/mylib)
add_executable(${MyAppName} ${MyApp_SOURCES})
target_link_libraries(${MyAppName} ${MyLibName}
The use of add_subdirectory ensures that mylib will be built before myapp and target_link_libraries adds mylib to the executable.
As mentioned by Tzalumen, make sure you take a look at the CMake tutorials and prefer the use of cmake --build . instead of make.
So, I actually do this in one of my projects.
First, the library needs to be built with ADD_LIBRARY(), but I'm assuming you do that. Something like
ADD_LIBRARY (${MyLibName} ${SOURCES}) in the library's CMakeLists.txt
That adds the library into cmake's list of libraries.
Second, you add the library to your project with
target_link_libraries (${PROJECT_NAME} ${MyLibName}) in the executable's CMakeLists.txt, the same one where you have your add_executable (${PROJECT_NAME} ${SOURCES})
That will set up the dependency chain to force MyLibName to explicitly build before PROJECT_NAME.
Related
to start with, I have the following repo structure.
root
|
|--- blocks
| |
| |---example
| |
| |---example.cpp
| |---CMakeLists.txt
|
|--- interfaces
|
|--- types
|
|-- types1.h
|-- types2.h
|-- CMakeLists.txt
What I would like to do is to only include types1.h in the cmake target of example.cpp. And I would like to include types1.h such that I can include it in example.cpp using its path relative to root (i.e. #include "interfaces/types/types1.h") and I don't want to use include_directories(${CMAKE_SOURCE_DIR}) since that would expose the whole repo to the target.
target_include_directories did not work since it only includes directories but not individual files and I don't want to include a whole directory and expose irrelevant headers in types folder to example.cpp or move types1.h to a dedicated subfolder.
Do you have any suggestions on how to achieve this?
My current solution is as below which gives fatal error: interfaces/types/types1.h: No such file or directory when I compile exampleblock target. (I eased the requirements for start and allowed interface_types target to include types2.h also even though example.cpp doesn't need it)
blocks/example/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
add_library(exampleblock STATIC
example.cpp
)
target_link_libraries(exampleblock INTERFACE
${CMAKE_SOURCE_DIR}/interfaces/types:interface_types
)
interfaces/types/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
add_library(interface_types INTERFACE)
target_include_directories(interface_types INTERFACE .)
My current project has the following structure:
root
|- parser
| |- include // a directory for headers
| |- src // a directory for sources
| |- parser.yy
| |- scanner.ll
| |- CmakeLists.txt
|
|- preprocessor
| |- include // a directory for headers
| |- src // a directory for sources
| |- CmakeLists.txt
|
|- main.cpp
|- CMakeLists.txt
Now I want to start generating assembly codes. I have to use staticstack and codegen (are classes which are going to be defined) in the parser.yy and in srcfolder of the parser foler.
I cannot figure out how to do that.
What's the best practice in CMake to do this ?
Should I make subdirectories named semstack and codegen in parser folder ? This doesn't seem correct to me since as a CMake project gets larger the hierarchy will get deeper and if more dependencies are there then it would be a mess.
Should I make these subdirectories in the root ? If then what is the syntax in CMake to use sibling subdirectory ?
If then what is the syntax in CMake to use sibling subdirectory ?
There is no special syntax for this since normal (i.e. not IMPORTED) targets are global. If you define a library in one subdirectory, it may be used in any other via target_link_libraries.
For instance:
# parser/CMakeLists.txt
add_library(parser ...)
add_library(proj::parser ALIAS parser)
target_include_directories(
parser PRIVATE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>")
target_link_libraries(
parser PRIVATE proj::semstack proj::codegen)
The code for other subdirectories is similar.
# ./CMakeLists.txt
cmake_minimum_required(VERSION 3.22)
project(proj)
add_subdirectory(semstack)
add_subdirectory(codegen)
add_subdirectory(parser)
add_subdirectory(preprocessor)
add_executable(main main.cpp)
target_link_libraries(
main PRIVATE proj::parser proj::preprocessor)
I create and link to ALIAS targets to avoid a typo in a target name being forwarded to the linker verbatim (names with :: in CMake are always considered targets and this is validated at generation time).
Having problems setting up a project to keep directory structure with cmake.
Project structure I want to keep:
Project
|-libA
| |-fileA.h
| |-fileA.cpp
| |-CMakeLists.txt
|-include
| |-fileI.h
|-program1
| |-main.cpp
| |-CMakeLists.txt
|-CMakeLists.txt
source code include example:
#include "libA/fileA.h"
This doesn't work. Cmake can't find "libA/fileA.h", it will only work if I create a following directory structure:
Project
|-libA
| |-libA (directory)
| |-fileA.h
| |-fileA.cpp
| |-CMakeLists.txt
|-include
| |-fileI.h
|-program1
| |-main.cpp
| |-CMakeLists.txt
|-CMakeLists.txt
What can I do to keep the project structure as shown in the first example and to keep directory name in source files? (eg #include "libA/fileA.h")
Project cmake:
cmake_minimum_required(VERSION 3.8)
project(A)
include_directories( ${PROJECT_SOURCE_DIR}/include )
add_subdirectory(libA)
add_subdirectory(program1)
libA cmake:
set(LIBA_SRC libA/fileA.cpp)
add_library(libA SHARED ${LIBA_SRC})
Program1 cmake:
set (PROGRAM1_SRC main.cpp)
add_executable (program1 ${PROGRAM_SRC})
target_link_libraries (program1 libA)
target_include_directories (program1 PUBLIC ${PROJECT_SOURCE_DIR}/libA)
If you change the include directory in program1 to
target_include_directories (program1 PUBLIC ${PROJECT_SOURCE_DIR})
it will search from your source directory, so "libA/fileA.h" will find it's target.
I have a batch script which when run will simply call a cmake command to build a visual studio C++ project. However, that project should have two references to two static libraries... yet, no matter what I try I can't seem to get my project to link the libraries correctly. Here's how my folder structure looks:
.
+-- build
| +-- x64
| +-- DebugStatic
| +-- mylibA_static.lib
| +-- mylibB_static.lib
+-- Include
+-- Source
+-- myproject
| +-- Demo
| +-- build
| +-- cmake
| +-- GenerateVS2015.bat
| +-- CMakeLists.txt
| +-- Demo.cpp
| +-- stdafx.cpp
Now, I'm running the batch script from within the cmake folder inside the Demo project folder structure. My batch script is as follows:
#echo off
set startingDir=%CD%
set basepath=%~dp0
set builddir=%basepath%\..\build
if not exist %builddir% (mkdir %builddir%)
cd %builddir%
cmake -G "Visual Studio 14 2015 Win64" .. %*
cd %startingDir%
Nothing too complicated. Now, let's look at the CMakeLists.txt file:
cmake_minimum_required (VERSION 2.8)
PROJECT (Demo)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# using Visual Studio C++
add_definitions(-DBUILD_DLL)
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} xmllite.lib")
string(REGEX REPLACE "/bin/[^/]*$" "" VCINSTALLDIR "${CMAKE_C_COMPILER}")
message(STATUS "Guessed MSVC directory: ${VCINSTALLDIR}")
endif()
SET(SRCS
Demo.cpp
stdafx.cpp
)
ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS})
TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME} PUBLIC ../../Include)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}../../build/x64/DebugStatic/mylibA_static.lib ${CMAKE_CURRENT_SOURCE_DIR}../../build/x64/DebugStatic/mylibB_static.lib)
Using this logic, wouldn't CMake build a Visual Studio C++ project called Demo.vcproj... and inside that project file would linked two libraries called mylibA_static.lib and mylibB_static.lib inside the references. However, when I try this, I never get any sort of linked library.
First, in your batch script, you only generated the makefiles, but you didn't actually build the library. So I would suggest you add the line make after cmake and before cd.
Second, I would suggest you surround all your strings with double quotes, in order to be specific, and avoid confusion between constants and variables. Also, it is better to add additional slashes. So, change
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}../../build/x64/DebugStatic/mylibA_static.lib ${CMAKE_CURRENT_SOURCE_DIR}../../build/x64/DebugStatic/mylibB_static.lib)
to
TARGET_LINK_LIBRARIES(${PROJECT_NAME} "${CMAKE_CURRENT_SOURCE_DIR}/../../build/x64/DebugStatic/mylibA_static.lib" "${CMAKE_CURRENT_SOURCE_DIR}/../../build/x64/DebugStatic/mylibB_static.lib)".
As for the relative pathes, I think you are fine. But be careful when you use CMAKE_SOURCE_DIR and CMAKE_CURRENT_SOURCE_DIR. Here are some notes from CMake Wiki:
CMAKE_CURRENT_SOURCE_DIR this is the directory where the currently
processed CMakeLists.txt is located in
CMAKE_SOURCE_DIR this is the directory which contains the top-level
CMakeLists.txt, i.e. the top level source directory
I've got a question on cmake project configuration.
The following is my project structure.
trunk
|
|---- mylib
| |
| ---- mylib.h
| ---- mylib.c
| ---- *MYLIB_CMakeList.txt*
|
|---- alib
| |
| ---- alib.h
| ---- alibName.lib
| ---- *ALIB_CMakeList.txt*
|
|
|---- main
| |
| ---- main.cpp
| ---- *MAIN_CMakeList.txt*
|
---- *TOP_CMakeList.txt*
mylib subfolder contains the source code (c) to create my own static library. This code depends on alib.
The main subfolder contains the example code (C++) which uses mylib.
Here is how I've written my CMakeList files:
**TOP_CMakeList.txt**
cmake_minimum_required(VERSION 3.4)
add_subdirectory(mylib)
add_subdirectory(alib)
add_subdirectory(main)
------------------------------------------------------------------------------------------------------------
**MYLIB_CMakeList.txt**
cmake_minimum_required(VERSION 3.4)
project(MyLib C)
if (WIN32)
set(CMAKE_SHARED_LIBRARY_PREFIX "")
endif ()
include_directories(${alib_INCLUDE_DIRS})
add_library(${PROJECT_NAME} STATIC mylib.c)
target_link_libraries(${PROJECT_NAME} alib)
set(${PROJECT_NAME}_DEFINITIONS CACHE INTERNAL "${PROJECT_NAME}: Definitions" FORCE)
set(${PROJECT_NAME}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR} CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)
------------------------------------------------------------------------------------------------------------
**ALIB_CMakeList.txt**
cmake_minimum_required(VERSION 3.4)
project(ALib)
set(${PROJECT_NAME}_DEFINITIONS CACHE INTERNAL "${PROJECT_NAME}: Definitions" FORCE)
set(${PROJECT_NAME}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR} CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)
------------------------------------------------------------------------------------------------------------
**MAIN_CMakeList**
make_minimum_required(VERSION 3.4)
project(Executable CPP)
file(GLOB CPP_FILES *.cpp)
add_definitions(${MyLib_DEFINITIONS})
include_directories(${MyLib_INCLUDE_DIRS})
add_executable(${PROJECT_NAME} ${CPP_FILES})
target_link_libraries(${PROJECT_NAME} MyLib)
With such configuration it doesn't recognize the alib dependency of mylib. In particular (I'm developing under Windows) I get this error:
/usr/lib/gcc/x86_64-pc-cygwin/4.9.3/../../../../x86_64-pc-cygwin/bin/ld:
cannot find -lalibName.lib
I can't figure out how to correctly do it. Any suggestions?
Seems that the alib project does not specify any kind of library targets the same way as mylib does:
Try adding this to alibs' CMake file
add_library(${PROJECT_NAME} STATIC <<< alib SOURCES HERE >>>)
Static libraries can't have dependencies(well, they can but they don't drag them with themselves) so there is no point in providing alib in target_link_libraries(...) for another static library. You should provide alib to the add_execuable command directly.
Alternatively, you can build a big static library from both mylib and alib but it will be less elegant and platfrom dependant. For gcc you should look at ar tool.
Remove the add_subdirectory(alib) command, then remove CMake file from the alib subfolder — you don't need it. Then in the cmake file where you have your add_executable command put the following(after the line);
link_directories(../alib)
target_link_libraries(${PROJECT_NAME} alibName.lib)