关于模块、CMake 和在动态链接库中使用模块的问题。

huangapple go评论70阅读模式
英文:

Question about modules, CMake and using modules in dll

问题

我花了很多时间尝试解决使用cpp 20模块在动态链接库中编译我的学习解决方案的问题。我的项目结构如下:

  • 主解决方案目录
    CMakeLists.txt
    -- 应用程序目录(可执行文件的源代码)
    --- 头文件
    .h文件
    --- 资源
    项目资源
    --- 源代码
    .cpp文件
    -- 库目录(项目的一些类)
    --- 包含文件
    .h文件
    --- 接口
    .ixx文件(模块本身)

如你所见,解决方案包含两个文件夹,我在父文件夹中有一个Cmake文件,用于从那里编译exe和dll。问题是 - 就好像它会在经典的头文件包含中工作一样,但在模块中不行,因为现在编译顺序很重要,这是我学到的。我只是在学习,关于如何使用模块的信息很少,我找不到如何安排我的CMake列表以使其纯粹通过控制台运行。

问题是,当运行cmake构建项目时 - 它找不到dll的.o文件,并且在构建链接时无法构建。dll必须以某种方式提前编译。

当我在VS Studio中打开项目时,如果我命令VS首先构建.dll,然后再命令构建所有内容,那么我可以构建它。然后它成功地编译了所有内容,因为模块中的文件据说是预先构建的,然后稍后使用。

有人有过如何编写CMake文件的经验吗,也许是带有子文件夹指令和分离的CMake列表,以使其正常运行吗?

我在父目录中有一个像这样的CMakeLists.txt:

cmake_minimum_required(VERSION 3.14.0)
set (CMAKE_CXX_STANDARD 20)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

project(RaceGame)

include_directories(
${PROJECT_SOURCE_DIR}/RaceApp/headers
${PROJECT_SOURCE_DIR}/RaceApp/src
${PROJECT_SOURCE_DIR}/RaceLib/interfaces
${PROJECT_SOURCE_DIR}/RaceLib/includes
)

link_directories(${PROJECT_SOURCE_DIR}/RaceApp/interaces)

file(GLOB Lib_SRCS
"${PROJECT_SOURCE_DIR}/RaceLib/interfaces/.ixx"
"${PROJECT_SOURCE_DIR}/RaceLib/includes/
.h"
)

file(GLOB App_SRCS
"${PROJECT_SOURCE_DIR}/RaceApp/headers/.h"
"${PROJECT_SOURCE_DIR}/RaceApp/src/
.cpp"
)

configure_file(${PROJECT_SOURCE_DIR}/RaceApp/resources/botnames.txt botnames.txt COPYONLY)
configure_file(${PROJECT_SOURCE_DIR}/RaceApp/resources/botcallsigns.txt botcallsigns.txt COPYONLY)

add_library(RaceLib SHARED ${Lib_SRCS} "${PROJECT_SOURCE_DIR}/RaceLib/includes/RaceLibExceptions.h")
add_executable(RaceGame ${App_SRCS} "${PROJECT_SOURCE_DIR}/RaceLib/includes/RaceLibExceptions.h")

target_link_libraries(RaceGame RaceLib)


我尝试了很多不同的想法,但是我对CMake的经验不足,无法解决这个问题。
英文:

I've spend a lot of time trying to figure out an issue of compiling the solution for my studies using the cpp 20 modules in dynamic linked library. I've got my project structure as following:

- Main soluition directory
CMakeLists.txt
-- Application directory (sources for executable)
--- headers
.h files
--- resources
some resources for project
--- src
.cpp files
-- Library directory (some classes for project)
--- includes
.h files
--- interfaces
.ixx file (the module itself)

As you can see the solution contains two folders and I've got 1 Cmake file in parent folder to compile both exe and dll from there. Thing is - as if this would work with classic header includes, it doesn't with modules as the compilation order matters now as I learned. I'm just learning and the info on how to work with modules is scarce, I couldn't find how to order up my CMake lists to make this work pure via console.

Problem is that when running cmake to build the project - it won't find the dll's .o file and fails to building linking. The dll must be compiled up front somehow.

When I open the project in VS studio I'm able to build it if I order VS to build the .dll first and THEN order to build all. Then it successfully complies everything as the files from modules are supposedly built upfront and used later.

Did anyone had any experience on how to structure the CMake file, maybe with subfolder directives and separated CMake lists, to make it run properly?

I've got a CMakeLists.txt in parent directory like this:

cmake_minimum_required(VERSION 3.14.0)
set (CMAKE_CXX_STANDARD 20)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

project(RaceGame)

include_directories(
        ${PROJECT_SOURCE_DIR}/RaceApp/headers
        ${PROJECT_SOURCE_DIR}/RaceApp/src
        ${PROJECT_SOURCE_DIR}/RaceLib/interfaces        
        ${PROJECT_SOURCE_DIR}/RaceLib/includes
)

link_directories(${PROJECT_SOURCE_DIR}/RaceApp/interaces)

file(GLOB Lib_SRCS
        "${PROJECT_SOURCE_DIR}/RaceLib/interfaces/*.ixx"
        "${PROJECT_SOURCE_DIR}/RaceLib/includes/*.h"
        )

file(GLOB App_SRCS
        "${PROJECT_SOURCE_DIR}/RaceApp/headers/*.h"
        "${PROJECT_SOURCE_DIR}/RaceApp/src/*.cpp"
        )
		
configure_file(${PROJECT_SOURCE_DIR}/RaceApp/resources/botnames.txt botnames.txt COPYONLY)
configure_file(${PROJECT_SOURCE_DIR}/RaceApp/resources/botcallsigns.txt botcallsigns.txt COPYONLY)

add_library(RaceLib SHARED ${Lib_SRCS} "RaceLib/includes/RaceLibExceptions.h")
add_executable(RaceGame ${App_SRCS} "RaceLib/includes/RaceLibExceptions.h")

target_link_libraries(RaceGame RaceLib)

I've been trying many different ideas but I just have not enough experience with CMake to work this out.

--------------- EDITED

cmake command output:

-- The C compiler identification is GNU 8.3.0
-- The CXX compiler identification is GNU 8.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/JINX/DEVELOPMENT/CRaceGame/build

cmake --build command output

[ 20%] Building CXX object CMakeFiles/RaceLib.dir/RaceLib/interfaces/RaceLib.ixx.o
c++: warning: /home/JINX/DEVELOPMENT/RaceGame/RaceLib/interfaces/RaceLib.ixx: linker input file unused because linking not done
[ 40%] Linking CXX shared library libRaceLib.so
c++: error: CMakeFiles/RaceLib.dir/RaceLib/interfaces/RaceLib.ixx.o: No such file or directory
make[2]: *** [CMakeFiles/RaceLib.dir/build.make:97: libRaceLib.so] Error 1
make[1]: *** [CMakeFiles/Makefile2:85: CMakeFiles/RaceLib.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

----------------------- EDIT 2

CMakeLists.txt

cmake_minimum_required(VERSION 3.25)

set (CMAKE_CXX_STANDARD 20)

set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

if (CMAKE_VERSION VERSION_LESS "3.26")
    # 3.25
    set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "3c375311-a3c9-4396-a187-3227ef642046")
elseif (CMAKE_VERSION VERSION_LESS "3.27")
    # 3.26
    set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
else ()
    message(FATAL_ERROR "See `https://github.com/Kitware/CMake/blob/v${CMAKE_VERSION}/Help/dev/experimental.rst`.")
endif (CMAKE_VERSION VERSION_LESS "3.26")
# turn on the dynamic depends for ninja
set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP ON)

project(RaceGame)

include_directories(
        RaceApp/headers
        RaceApp/src
        RaceLib/interfaces        
        RaceLib/includes
)

link_directories(RaceApp/interaces)

file(GLOB Lib_SRCS
        "RaceLib/interfaces/*.ixx"
        )

file(GLOB App_SRCS
        "RaceApp/src/*.cpp"
        )
		
configure_file(RaceApp/resources/botnames.txt botnames.txt COPYONLY)
configure_file(RaceApp/resources/botcallsigns.txt botcallsigns.txt COPYONLY)

add_library(RaceLib SHARED)

target_sources(
        RaceLib
        PRIVATE
        FILE_SET module_files
        TYPE CXX_MODULES
        BASE_DIRS "${PROJECT_SOURCE_DIR}"
        FILES

        ${PROJECT_SOURCE_DIR}/RaceLib/interfaces/RaceLib.ixx
)

add_executable(RaceGame ${App_SRCS})

target_link_libraries(RaceGame RaceLib)

cmake command output

-- Building for: Visual Studio 17 2022
-- Selecting Windows SDK version 10.0.22000.0 to target Windows 10.0.19045.
-- The C compiler identification is MSVC 19.35.32215.0
-- The CXX compiler identification is MSVC 19.35.32215.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/Development/MS VS 2022 Community/VC/Tools/MSVC/14.35.32215/bin/Hostx64/x64/cl.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/Development/MS VS 2022 Community/VC/Tools/MSVC/14.35.32215/bin/Hostx64/x64/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
CMake Warning (dev) at CMakeLists.txt:43 (target_sources):
  CMake's C++ module support is experimental.  It is meant only for
  experimentation and feedback to CMake developers.
This warning is for project developers.  Use -Wno-dev to suppress it.

-- Configuring done (7.6s)
CMake Warning (dev):
  C++20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
  experimental.  It is meant only for compiler developers to try.
This warning is for project developers.  Use -Wno-dev to suppress it.

-- Generating done (0.1s)
-- Build files have been written to: D:/Development/SOLUTIONS/RaceGame/build

cmake --build output:

MSBuild version 17.5.0+6f08c67f3 for .NET Framework

  Checking Build System
  Building Custom Rule D:/Development/SOLUTIONS/RaceGame/CMakeLists.txt
  Scanning sources for module dependencies...
  RaceLib.ixx
  Compiling...
  RaceLib.ixx

... some my code warnings

Auto build dll exports
  Couldn't open file 'D:/Development/SOLUTIONS/RaceGame/build/RaceLib.dir/Debug/RaceLib.obj' with Crea
  teFile()

... errors

答案1

得分: 2

据我所知,要使用`module`,CMake的版本要求相对较高。

你可能需要的是[target_sources][1]。

你可以使用:
```cmake
cmake_minimum_required(VERSION 3.25)

if (CMAKE_VERSION VERSION_LESS "3.26")
	# 3.25
	set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "3c375311-a3c9-4396-a187-3227ef642046")
elseif (CMAKE_VERSION VERSION_LESS "3.27")
	# 3.26
	set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
else ()
	message(FATAL_ERROR "See `https://github.com/Kitware/CMake/blob/v${CMAKE_VERSION}/Help/dev/experimental.rst`.")
endif (CMAKE_VERSION VERSION_LESS "3.26")
# 打开Ninja的动态依赖
set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP ON)

add_library(my_module_library)

# 模块源文件
target_sources(
		my_module_library
		PRIVATE
		FILE_SET module_files
		TYPE CXX_MODULES
		BASE_DIRS "${PROJECT_SOURCE_DIR}"
		FILES

		"${PROJECT_SOURCE_DIR}/src/my_module.ixx"
)

# 头文件
target_sources(
		my_module_library
		PUBLIC
		FILE_SET header_files
		TYPE HEADERS
		BASE_DIRS "${PROJECT_SOURCE_DIR}/src"
		FILES

		"${PROJECT_SOURCE_DIR}/src/my_header.hpp"
)

<details>
<summary>英文:</summary>

As far as I know, to use the `module`, CMake version requirements are relatively high.

What you may need is [target_sources][1]

You can use:
```cmake
cmake_minimum_required(VERSION 3.25)

if (CMAKE_VERSION VERSION_LESS &quot;3.26&quot;)
	# 3.25
	set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API &quot;3c375311-a3c9-4396-a187-3227ef642046&quot;)
elseif (CMAKE_VERSION VERSION_LESS &quot;3.27&quot;)
	# 3.26
	set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API &quot;2182bf5c-ef0d-489a-91da-49dbc3090d2a&quot;)
else ()
	message(FATAL_ERROR &quot;See `https://github.com/Kitware/CMake/blob/v${CMAKE_VERSION}/Help/dev/experimental.rst`.&quot;)
endif (CMAKE_VERSION VERSION_LESS &quot;3.26&quot;)
# turn on the dynamic depends for ninja
set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP ON)

add_library(my_module_library)

# MODULE SOURCE
target_sources(
		my_module_library
		PRIVATE
		FILE_SET module_files
		TYPE CXX_MODULES
		BASE_DIRS &quot;${PROJECT_SOURCE_DIR}&quot;
		FILES

		${PROJECT_SOURCE_DIR}/src/my_module.ixx
)

# HEADER FILES
target_sources(
		my_module_library
		PUBLIC
		FILE_SET header_files
		TYPE HEADERS
		BASE_DIRS &quot;${PROJECT_SOURCE_DIR}/src&quot;
		FILES

		${PROJECT_SOURCE_DIR}/src/my_header.hpp
)

答案2

得分: 1

最后,我只是将库编译为静态库,而不是共享库。虽然它能运行。这不是我想要的,但这是我得到的结果。

英文:

In the end I just switched the library to compile as STATIC library instead of SHARED. It works, tho. That's not what I wanted, but that's what I've got working.

huangapple
  • 本文由 发表于 2023年3月9日 16:02:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/75681851.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定