CMake Reminder
Build-Requirements of A Target
Everything that is needed to build that target.
- source-files
- include search-paths
- pre-processor macros
- link-dependencies
- compiler/linker-options
- compiler/linker-features(e.g. support for a C++-standard)
Usage-Requirements of A Target
Everything that is needed to (successfully) use that target.
As a dependency of another target.
- Same as Build-Requirements, but source-files are normally not required.
# Adding build-requirements
target_include_directories( <target> PRIVATE <include-search-dir>... )
target_compile_definitions( <target> PRIVATE <macro-definitions>... )
target_compile_options( <target> PRIVATE <compiler-option>... )
target_compile_features( <target> PRIVATE <feature>... )
target_sources( <target> PRIVATE <source-file>... )
target_link_libraries( <target> PRIVATE <dependency>... )
target_link_options( <target> PRIVATE <linker-option>... )
target_link_directories( <target> PRIVATE <linker-search-dir>... )
# Adding usage-requirements
target_include_directories( <target> INTERFACE <include-search-dir>... )
#...more...
#Adding build-and-usage requirements
target_include_directories( <target> PUBLIC <include-search-dir>... )
#...more...
⚠️ Although target_link_libraries can be used without these keywords, you should never forget to use these keywords in Modern CMake!
Keyword PUBLIC, INTERFACE, PRIVATE in CMake:
- PRIVATE: refer to build-requirement for a target. Only affect the current target, invisible ouside the target.
- INTERFACE: refer to usage-requirement for a target. propagate the dependency outside of the target. A dependency which is not used by the implementation of a library, but only by its headers should be specified as an- INTERFACEdependency.
 for example: main.cpp depends on hello_world.lib, and main.cpp calls functions in hello.lib. So we should write
target_link_libraries(hello-world INTERFACE hello)
target_include_directories(hello-world INTERFACE hello)
- PUBLIC: refer to build & usage-requirement. propogate the dependecy outside of the target.
Keyword add_library
Normal Library
add_library(<name> [STATIC | SHARED | MODULE]
            [EXCLUDE_FROM_ALL]
            [<source>...])
- STATIClibraries are archives of object files for use when linking other targets.
- SHAREDlibraries are linked dynamically and loaded at runtime.
- MODULElibraries are plugins that are not linked into other targets but may be loaded dynamically at runtime using dlopen-like functionality.
Object Libraries
add_library(<name> OBJECT [<source>...])
- An OBJECTlibrary compiles source files but does not archive or link their object files into a library.
Interface Libraries (refer to header-only lib)
add_library(<name> INTERFACE)
- An INTERFACElibrary target does not directly create build output, though it may have properties set on it and it may be installed, exported and imported.
Adding Build/Usage Requirements to Targets
- Usage-requirements of dependencies need to become build-requirements of dependent targets using the same commands.
- Since CMake 3.12 the target_link_librariescommand can be used withOBJECTtargets.- Usage-requirements of dependencies can be propagated to OBJECTtargets.
 
- Usage-requirements of dependencies can be propagated to 
More about propagation OBJECT peculiarities
A Quiz:
# A common object-library target.
add_library( commonObjLib OBJECT )
target_sources( commonObjLib PRIVATE "common.cpp" )
target_include_directories( commonObjLib PUBLIC "include/common" )
# A shared-library target.
add_library( sharedLib1 SHARED )
# Another object-library target...
add_library( objLib2 OBJECT )
target_sources( objLib2 PRIVATE "source2.cpp" )
target_include_directories( objLib2 PUBLIC "include2" )
# ... and yet another one.
add_library( objLib3 OBJECT )
target_sources( objLib3 PRIVATE "source3.cpp" )
target_include_directories( objLib3 PUBLIC "include3" )
# Dependency on 'commonObjLib'.
target_link_libraries( sharedLib1 PUBLIC commonObjLib )
target_link_libraries( objLib2 PRIVATE commonObjLib )
target_link_libraries( objLib3 INTERFACE commonObjLib )
# Create executables linked against these targets.
add_executable( exe1 )
add_executable( exe2 )
add_executable( exe3 )
target_sources( exe1 PRIVATE "main1.cpp" )
target_sources( exe2 PRIVATE "main2.cpp" )
target_sources( exe3 PRIVATE "main3.cpp" )
target_link_libraries( exe1 PRIVATE sharedLib1 )
target_link_libraries( exe2 PRIVATE objLib2 )
target_link_libraries( exe3 PRIVATE objLib3 )
Question1: What (local) include-directories does each individual target (exe1, exe2 and exe3) know during compilation?
Answer: 
exe1 — . and include/common
exe2 — . and include2
exe3 — . and include3 and include/common
Question2: The generated output-binary of which executable target (exe1, exe2 or exe3) contains the object-files for common.cpp?
Answer: 
None! — Only the output-binary of sharedLib
contains the object-files received from
commonObjLib.
The reason: Rules For Linking OBJECT Library Targets
- Usage-requirements of any target (even OBJECTlibrary targets) on the right-hand-side of target_link_libraries are propagated to theOBJECTlibrary target on the left-hand-side.
- Object-files(.obj) are only ever propagated to direct dependants! And only, if that direct dependant is not an OBJECTlibrary target itself.
# Knowing usage-requirements from 'anyTarget' when compiling to object-files,
# but not further propagating them to other targets.
# usage-requirement of anyTarget => build-requirements of objTarget
target_link_libraries( objTarget PRIVATE anyTarget )
# Not knowing usage-requirements from 'anyTarget' when compiling to object-files,
# but further propagating them to other targets.
# usage-requirement of anyTarget => usage-requirements of objTarget
target_link_libraries( objTarget INTERFACE anyTarget )
# Knowing usage-requirements from 'anyTarget' when compiling to object-files,
# and further propagating them to other targets.
# usage-requirement of anyTarget => usage/build-requirements of objTarget
target_link_libraries( objTarget PUBLIC anyTarget )
# Object-files are only propagated to the build-requirements of another target
# if that other target is not an OBJECT library target itself!
# Object-files of objTarget => build-requirements of nonObjTarget
# Object-files of objTarget !=> build/usage-requirements of otherObjTarget
target_link_libraries( nonObjTarget PRIVATE objTarget ) # Directly propagate object-files.
target_link_libraries( otherObjTarget PRIVATE objTarget ) # No propagation of object-files.
# No object-files can be propagated to the usage-requirements of any other target!
target_link_libraries( anyTarget INTERFACE objTarget ) # No indirect propagation of object-files.
# Object-files are propagated exactly as for PRIVATE propagation of object-files.
# Object-files of objTarget => build-requirements of nonObjTarget
# Object-files of objTarget !=> build/usage-requirements of otherObjTarget
target_link_libraries( nonObjTarget PUBLIC objTarget ) # Directly propagate object-files.
target_link_libraries( otherObjTarget PUBLIC objTarget ) # No propagation of object-files.
Creating Targets from OBJECT Targets
- Object-files from the OBJECTtarget are the sources of theSHAREDlibrary target.
Linking All Together Into Executables
include_directories( "../library/include" ) # This is ugly!
Avoid relative path. In mordern Cmake. Dependencies propagate their include-search paths automatically, together with all other usage-requirements.
add_compile_options(), CMAKE_CXX_FLAGS, target_compile_options()
- add_compile_options()does append to the- COMPILE_OPTIONSdirectory property and is taken as default for all- COMPILE_OPTIONSproperties of targets coming after the- add_compile_options()command. So make sure- add_compile_options()command is before the- add_library()/- add_executable().- Adds options to the compiler command line for targets in the current directory and below that are added after this command is invoked. 
- CMAKE_CXX_FLAGSapplies to all targets in the current CMakeLists.txt. Do not use- CMAKE_CXX_FLAGS. It’s not transitive, and is a global bulid requirements.
- target_compile_options(): Add compile option with fine grained control of transition (Use this in the most of condition!).
#Dont do this!
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" CACHE
     STRING "C++ compile-flags" FORCE )
#Do this
target_compile_features( basicmath_ObjLib
    PUBLIC cxx_constexpr )
VSCode相關設定
Configure arguments的寫法,以opencv為例:
-DOPENCV_EXTRA_MODULES_PATH=C:/Users/MSI/source/repos/opencv_contrib/modules
- 加在Cmake: Configure Args變數內
- 要加上-D
- 路徑linux型斜線,不加雙引號""