Advertisement

How to get dependencies, libraries, and include path in external project of cmake

Started by June 02, 2023 03:29 PM
1 comment, last by dimi309 1 year, 6 months ago

Now I'm trying to make an ECS Project.

Therefore, the Memory Project is used as an external project, and the Memory Project is using the Log Project as an external project.

In other words, it has the following dependence.

ECS -> Memory -> Log

However, at this time, I would like to make the ECS Project use the dependency on the Log of the Memory Project and the information on the Log library and header file.

To do that, I wonder how ECS Project can also have Library information, Dependency information, and Header file information.

Thank you for reading the question.

< ECS CMakelists.txt>

# ------ Set Options for Projects --------------- #
MESSAGE( STATUS "Set Options for Project")

## CMake minimun version required
CMAKE_MINIMUM_REQUIRED( VERSION 3.11 )

## Make Project Name
SET( PROJECT_NAME "ECSProject" )
## Project name
PROJECT( ${PROJECT_NAME} )

SET(CMAKE_BUILD_TYPE Debug)
if( MSVC )
	MESSAGE( STATUS "Compiler is ${CMAKE_CXX_COMPILER_ID}")
    # Use multi-process debugging
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi /MP")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Zi /MP")

    # Use Windbg as the debugger
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /DEBUG:FULL")
    set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /DEBUG:FULL")
    set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} /DEBUG /INCREMENTAL:NO")
endif()

## Set CXX Compiler Version
SET( CMAKE_CXX_STANDARD 17 )
## Set Exe file place
SET( RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR} )

MESSAGE( STATUS "Setting Done")
# ----------------------------------------------- #



# ------ Set Files ------------------------------ #
MESSAGE( STATUS "Set Source File")

INCLUDE( Dependency.cmake )

## Source Files
LIST( APPEND SRCS

    ## Demo file
    ${SRC_DIR}/main.cpp
    )

## Header Files
LIST( APPEND INCS )

MESSAGE( STATUS "Setting Done ")
# ----------------------------------------------- #



# ------ Set Options for Target Files ----------- #
MESSAGE( STATUS "Set Options for Target Files")

## Include Header Directories for Target Files
ADD_EXECUTABLE( ${PROJECT_NAME} WIN32 ${SRCS} )

TARGET_INCLUDE_DIRECTORIES( ${PROJECT_NAME} PUBLIC ${INCS} ${DEP_INCLUDES} )
TARGET_LINK_DIRECTORIES( ${PROJECT_NAME} PUBLIC ${DEP_LIB_DIR} )
TARGET_LINK_LIBRARIES( ${PROJECT_NAME} PUBLIC ${DEP_LIBS} )
ADD_DEPENDENCIES( ${PROJECT_NAME} ${DEP_LIST} )

MESSAGE( STATUS "Setting Done ")
# ----------------------------------------------- #

< ECS Dependency.cmake >

# ------ Set for ExternalProject ---------------- #
MESSAGE( STATUS "Setting for ExternalProject")

INCLUDE( ExternalProject )

MESSAGE( STATUS "Setting Done")
# ----------------------------------------------- #



# ------ Set Variables for Dependency ----------- #
MESSAGE( STATUS "Setting Variables for Dependency")

SET( MAIN_DIR ${CMAKE_SOURCE_DIR} )

SET( SRC_DIR ${MAIN_DIR}/src )

SET( SRCS )
SET( INCS )

SET( DEP_INSTALL_DIR ${PROJECT_BINARY_DIR}/install )
SET( DEP_INCLUDE_DIR ${DEP_INSTALL_DIR}/include )
SET( DEP_LIB_DIR ${DEP_INSTALL_DIR}/lib )
SET( DEP_BIN_DIR ${DEP_INSTALL_DIR}/bin )
SET( DEP_CONFIG_DIR ${DEP_INSTALL_DIR}/config )

SET( DEP_LIST )
SET( DEP_CONFIGS )
SET( DEP_INCLUDES )
SET( DEP_LIBS )
SET( DEP_BINS )

MESSAGE( STATUS "Setting Done")
# ----------------------------------------------- #



#### Memory Pool ----------------------------------- #
MESSAGE(STATUS "Memory Project - Linking ...")

EXTERNALPROJECT_ADD(
    MemoryProject
    GIT_REPOSITORY GIT_REPOSITORY https://github.com/Winteradio/MemoryPool.git
    GIT_TAG "v2.0.8"

    PREFIX ${CMAKE_BINARY_DIR}/Prefix/MemoryProject

    UPDATE_COMMAND "" PATCH_COMMAND "" TEST_COMMAND "" INSTALL_COMMAND ""
    CMAKE_ARGS
        -DINCLUDE_DIR=${DEP_INCLUDE_DIR}
        -DLIB_DIR=${DEP_LIB_DIR}
        -DBIN_DIR=${DEP_BIN_DIR}
        -DCMAKE_BUILD_TYPE=Debug
        -DBUILD_STATIC_LIBRARY=ON
        -DINSTALL_DEMO_FILE=OFF
        -DINSTALL_MEMORY_MANAGER=ON
)

LIST( APPEND DEP_INCLUDE ${DEP_INCLUDE_DIR}/MemoryProject ${DEP_INCLUDE_DIR}/LogProject )
LIST( APPEND DEP_LIBS ${DEP_LIB_DIR} )
LIST( APPEND DEP_LIST MemoryProject)

MESSAGE(STATUS "memoryPool - Done")
#### MemoryPool ----------------------------------- #

< Memory Project CMakelists.txt >

# ------ Set Options for Projects --------------- #
MESSAGE( STATUS "Set Options for Project")

## CMake minimum version required
CMAKE_MINIMUM_REQUIRED( VERSION 3.11 )

## Make Project Name
SET( PROJECT_NAME "MemoryProject" )
## Project name
PROJECT( ${PROJECT_NAME} )

# Option to set the build type
SET(CMAKE_BUILD_TYPE Debug CACHE STRING "Build Type")

if( MSVC )
    MESSAGE( STATUS "Compiler is ${CMAKE_CXX_COMPILER_ID}")
    # Use multi-process debugging
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi /MP")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Zi /MP")

    # Use Windbg as the debugger
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /DEBUG:FULL")
    set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /DEBUG:FULL")
    set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} /DEBUG /INCREMENTAL:NO")
endif()

## Set CXX Compiler Version
SET( CMAKE_CXX_STANDARD 17 )
## Set Exe file place
SET( RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR} )

MESSAGE( STATUS "Setting Done")
# ----------------------------------------------- #



# ------ Set Path ------------------------------ #
MESSAGE( STATUS "Set Path ")

## Set Directories
SET( MAIN_DIR ${CMAKE_SOURCE_DIR} )
SET( DEMOFILE_DIR ${MAIN_DIR}/demofile )
SET( MEMORYMANAGER_DIR ${MAIN_DIR}/MemoryManager )
SET( MEMORYPOOL_DIR ${MAIN_DIR}/OnlyMemoryPool )
SET( SOURCE_DIR )
SET( FOLDER_DIR )

MESSAGE( STATUS "Setting Done ")
# ------------------------------------------------ #



# ------- Set Option ----------------------------- #
MESSAGE( STATUS "Set Option" )

## Set Option for the library is dynamics or static, the main install is memory manager or memory pool and the demo file is installed or not
OPTION( BUILD_STATIC_LIBRARY "Set option for the library which is static or dynamic" ON )
OPTION( INSTALL_MEMORY_MANAGER "Install Memory Manager or Memory Pool" ON )
OPTION( INSTALL_DEMO_FILE "Install demofile for memorymanager" ON )
## Set Option for install lib, header files' path
SET( CONFIG_DIR ${MAIN_DIR}/config CACHE PATH "Config files for include, lib, bin" )
SET( INCLUDE_DIR ${MAIN_DIR}/include CACHE PATH "Header files Path" )
SET( LIB_DIR ${MAIN_DIR}/lib CACHE PATH "Library files Path" )
SET( BIN_DIR ${MAIN_DIR}/bin CACHE PATH "Execute files Path" )

INCLUDE( Dependency.cmake )

MESSAGE( STATUS ${CMAKE_BUILD_TYPE} )

IF ( INSTALL_DEMO_FILE )
    ADD_SUBDIRECTORY( ${DEMOFILE_DIR} )
    MESSAGE( STATUS "Install Demofile that use MemoryManager" )
ELSE()
    MESSAGE( STATUS "Do not install Demofile" )
ENDIF()

IF ( INSTALL_MEMORY_MANAGER )
    INCLUDE_DIRECTORIES( ${MEMORYMANAGER_DIR} )
    LIST( APPEND FOLDER_DIR ${MEMORYMANAGER_DIR} )
    LIST( APPEND SOURCE_DIR 
        ${FOLDER_DIR}/IMemoryPool.h 
        ${FOLDER_DIR}/MemoryPool.h
        ${FOLDER_DIR}/MemoryManager.h ${FOLDER_DIR}/MemoryManager.cpp
        )
    MESSAGE( STATUS "Install Memory Manager" )
ELSE()
    INCLUDE_DIRECTORIES( ${MEMORYPOOL_DIR} )
    LIST( APPEND FOLDER_DIR ${MEMORYPOOL_DIR} )
    LIST( APPEND SOURCE_DIR 
        ${FOLDER_DIR}/MemoryPool.h ${FOLDER_DIR}/MemoryPool.cpp
        )
    MESSAGE( STATUS "Install only Memory Pool" )
ENDIF()

MESSAGE( STATUS "Setting Done ")
# ----------------------------------------------- #



# ------ Create library ---------------- #
MESSAGE(STATUS "Create Library ")

IF ( BUILD_STATIC_LIBRARY )
    ADD_LIBRARY( ${PROJECT_NAME} STATIC ${SOURCE_DIR} )
    MESSAGE( STATUS "Build library as a static" )
ELSE ()
    ADD_LIBRARY( ${PROJECT_NAME} SHARED ${SOURCE_DIR} )
    MESSAGE( STATUS "Build library as a dynamic" )
ENDIF()

IF ( CMAKE_BUILD_TYPE MATCHES Debug )
    SET_TARGET_PROPERTIES( ${PROJECT_NAME} PROPERTIES
        ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${LIB_DIR}
        LIBRARY_OUTPUT_DIRECTORY_DEBUG ${LIB_DIR}
        RUNTIME_OUTPUT_DIRECTORY_DEBUG ${BIN_DIR}
    )
    MESSAGE( STATUS "Build library on Debug mode" )
ELSEIF ( CMAKE_BUILD_TYPE MATCHES Release )
    SET_TARGET_PROPERTIES( ${PROJECT_NAME} PROPERTIES
        ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${LIB_DIR}
        LIBRARY_OUTPUT_DIRECTORY_RELEASE ${LIB_DIR}
        RUNTIME_OUTPUT_DIRECTORY_RELEASE ${BIN_DIR}
    )
    MESSAGE( STATUS "Build library on Release mode" )
ELSE()
    SET_TARGET_PROPERTIES( ${PROJECT_NAME} PROPERTIES
        ARCHIVE_OUTPUT_DIRECTORY ${LIB_DIR}
        LIBRARY_OUTPUT_DIRECTORY ${LIB_DIR}
        RUNTIME_OUTPUT_DIRECTORY ${BIN_DIR}
    )
    MESSAGE( STATUS "Build library on Other mode" )
ENDIF()

FILE( COPY ${FOLDER_DIR}/ DESTINATION ${INCLUDE_DIR}/${PROJECT_NAME}
    FILES_MATCHING PATTERN "*.h" )

MESSAGE( STATUS "Creating Done ")
# ----------------------------------------------- #



# ------ Set Options for Target Files ----------- #
MESSAGE(STATUS "Set Options for Target Files")

TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME} PUBLIC ${INCS} ${DEP_INCLUDE})
TARGET_LINK_DIRECTORIES(${PROJECT_NAME} PUBLIC ${DEP_LIB_DIR})
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PUBLIC ${DEP_LIBS})
ADD_DEPENDENCIES(${PROJECT_NAME} ${DEP_LIST})

# Generate the configuration file
set(CONFIG_CONTENT "set(${PROJECT_NAME}_INCLUDE_DIR ${DEP_INCLUDE})\n")
set(CONFIG_CONTENT "${CONFIG_CONTENT}set(${PROJECT_NAME}_LIB_DIR ${DEP_LIBS})\n")

# Write the configuration file
file(WRITE ${CONFIG_DIR}/MemoryProjectConfig.cmake ${CONFIG_CONTENT})

MESSAGE(STATUS "Setting Done ")
# ----------------------------------------------- #

< Memory Project Dependency.cmake >

# ------ Set for ExternalProject ---------------- #
MESSAGE( STATUS "Setting for ExternalProject")

INCLUDE( ExternalProject )

MESSAGE( STATUS "Setting Done")
# ----------------------------------------------- #



# ------ Set Variables for Dependency ----------- #
MESSAGE( STATUS "Setting Variables for Dependency")

SET( DEP_INCLUDE )
SET( DEP_LIBS )
SET( DEP_LIST )

MESSAGE( STATUS "Setting Done")
# ----------------------------------------------- #



#### Log ----------------------------------- #
MESSAGE( STATUS "Log Project - Linking ... ")

EXTERNALPROJECT_ADD(
	LogProject
	GIT_REPOSITORY GIT_REPOSITORY https://github.com/Winteradio/Log.git
	GIT_TAG "v1.0.4"

	PREFIX ${CMAKE_BINARY_DIR}/Prefix/LogProject

	UPDATE_COMMAND "" PATCH_COMMAND "" TEST_COMMAND "" INSTALL_COMMAND ""
	CMAKE_ARGS 
		-DINCLUDE_DIR=${INCLUDE_DIR}
		-DLIB_DIR=${LIB_DIR}
		-DBIN_DIR=${BIN_DIR}
		-DCMAKE_BUILD_TYPE=Debug
		-DBUILD_STATIC_LIBRARY=ON
 		-DINSTALL_DEMO_FILE=OFF 
)
LIST( APPEND DEP_INCLUDE ${INCLUDE_DIR}/LogProject )
LIST( APPEND DEP_LIST LogProject )
LIST( APPEND DEP_LIBS ${LIB_DIR}/LogProject.lib )

MESSAGE( STATUS "Log Project - Done")
#### Log ----------------------------------- #

< Log Project CMakelists.txt >

# ------ Set Options for Projects --------------- #
MESSAGE( STATUS "Set Options for Project" )

## CMake minimum version required
CMAKE_MINIMUM_REQUIRED(VERSION 3.11)
## Make Project Name
SET(PROJECT_NAME "LogProject" )
## Project name
PROJECT(${PROJECT_NAME})
## Set C++ Compiler Version : C++17
SET( CMAKE_CXX_STANDARD 17 )

MESSAGE( STATUS "Setting Done" )
# ----------------------------------------------- #



# ------ Set Path ------------------------------ #
MESSAGE( STATUS "Set Path" )

## Set Directories
SET( MAIN_DIR ${CMAKE_SOURCE_DIR} )
SET( DEMOFILE_DIR ${MAIN_DIR}/demofile )
SET( LOG_DIR ${MAIN_DIR}/Log )
SET( SOURCE_DIR )

MESSAGE( STATUS "Setting Done" )
# ------------------------------------------------ #



# ------ Set Option ----------------------------- #
MESSAGE( STATUS "Set Option" )

OPTION( BUILD_STATIC_LIBRARY "Set option for the library which is static or dynamic" ON )
OPTION( INSTALL_DEMO_FILE "Install demofile for Log" OFF )
## Set Option for install lib, header files' path
SET( INCLUDE_DIR ${MAIN_DIR}/include CACHE PATH "Header files Path" )
SET( LIB_DIR ${MAIN_DIR}/lib CACHE PATH "Library files Path" )
SET( BIN_DIR ${MAIN_DIR}/bin CACHE PATH "Execute files Path" )
SET( CMAKE_BUILD_TYPE Debug CACHE STRING "Build Type")

MESSAGE( STATUS ${CMAKE_BUILD_TYPE} )

IF ( INSTALL_DEMO_FILE )
    ADD_SUBDIRECTORY( ${DEMOFILE_DIR} )
    MESSAGE( STATUS "Install Demofile that use Log" )
ELSE()
    MESSAGE( STATUS "Do not install Log's Demofile" )
ENDIF()

INCLUDE_DIRECTORIES( ${LOG_DIR} )
LIST( APPEND SOURCE_DIR 
    ${LOG_DIR}/Timer.h ${LOG_DIR}/Timer.cpp 
    ${LOG_DIR}/Log.h ${LOG_DIR}/Log.cpp
    )

MESSAGE( STATUS "Setting Done ")
# ----------------------------------------------- #


# ------ Create library ---------------- #
MESSAGE(STATUS "Create Library ")

IF ( BUILD_STATIC_LIBRARY )
    ADD_LIBRARY( ${PROJECT_NAME} STATIC ${SOURCE_DIR} )
    MESSAGE( STATUS "Build library as a static" )
ELSE ()
    ADD_LIBRARY( ${PROJECT_NAME} SHARED ${SOURCE_DIR} )
    MESSAGE( STATUS "Build library as a dynamic" )
ENDIF()

IF ( CMAKE_BUILD_TYPE MATCHES Debug )
    SET_TARGET_PROPERTIES( ${PROJECT_NAME} PROPERTIES
        ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${LIB_DIR}
        LIBRARY_OUTPUT_DIRECTORY_DEBUG ${LIB_DIR}
        RUNTIME_OUTPUT_DIRECTORY_DEBUG ${BIN_DIR}
    )
    MESSAGE( STATUS "Build library on Debug mode" )
ELSEIF ( CMAKE_BUILD_TYPE MATCHES Release )
    SET_TARGET_PROPERTIES( ${PROJECT_NAME} PROPERTIES
        ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${LIB_DIR}
        LIBRARY_OUTPUT_DIRECTORY_RELEASE ${LIB_DIR}
        RUNTIME_OUTPUT_DIRECTORY_RELEASE ${BIN_DIR}
    )
    MESSAGE( STATUS "Build library on Release mode" )
ELSE()
    SET_TARGET_PROPERTIES( ${PROJECT_NAME} PROPERTIES
        ARCHIVE_OUTPUT_DIRECTORY ${LIB_DIR}
        LIBRARY_OUTPUT_DIRECTORY ${LIB_DIR}
        RUNTIME_OUTPUT_DIRECTORY ${BIN_DIR}
    )
    MESSAGE( STATUS "Build library on Other mode" )
ENDIF()

FILE( COPY ${LOG_DIR}/ DESTINATION ${INCLUDE_DIR}/${PROJECT_NAME}
    FILES_MATCHING PATTERN "*.h" )

MESSAGE( STATUS "Creating Done ")
# ----------------------------------------------- #

I want to get Memory Project's Dependencies, libraries and Header files' directory through ExternalProject … to ECS Project's Include directory and library directory.

Normally targets (what is declared with ADD_LIBRARY or ADD_EXECUTABLE) carry this information with them if you declare them under the same project and link them together using PUBLIC for the “dependecy” libraries.

For example:

PROJECT(MyProject)
ADD_LIBRARY(LOGLIB logmain.cpp)
TARGET_INCLUDE_DIRECTORIES(LOGLIB PUBLIC "some/include/dir")
TARGET_LINK_LIBRARIES(LOGLIB PUBLIC "some.lib")
ADD_LIBRARY(MEMORYLIB memmain.cpp)
TARGET_LINK_LIBRARIES(MEMORYLIB PUBLIC "another.lib" LOGLIB) # MEMORYLIB links to "another.lib" LOGLIB and "some.lib"
                                                             # It should even get access to "some/include/dir"
ADD_EXECUTABLE(ECS ecsmain.cpp)
TARGET_LINK_LIBRARIES(ECS PRIVATE MEMORYLIB) # Links to all of the above

If you are wondering how to combine the three projects while keeping the code separate, you could do it with one project with three subdirectories. The CMakeLists.txt in the main folder could then have a command like subdirs(logdir memdir ecsdir) (the three being subdirectories for each project, each with its own CMakeLists.txt)

Another way is to compile LOG and MEMORY first and write Find modules for them which provide actual targets and not just strings to library and directory dependencies. You use LOG's find module to link to it when compiling MEMORY and then the MEMORY find module to link ECS to it. I do something like that here for my small3d library which needs a bunch of other libraries to work, declaring the target small3d::small3d in the Find module:

https://github.com/dimi309/small3d/blob/master/cmake/Findsmall3d.cmake

Then, when I use the library in a game, all I have to do is link the game program to it like this:

target_link_libraries(game PRIVATE small3d::small3d)

… and all small3d's dependencies come with it. I do not need to link the game to them separately.

I hope this helps. I have written it off the top of my head so, if anybody spots any mistake, please feel free to comment! ?

This topic is closed to new replies.

Advertisement