【问题标题】:CMake cannot link library correctlyCMake 无法正确链接库
【发布时间】:2023-09-13 12:59:01
【问题描述】:

我正在做作业,我的项目树是

.
├── CMakeLists.txt
├── main.c
├── src
│   ├── CMakeLists.txt
│   ├── game
│   │   ├── game.c
│   │   └── game.h
│   └── main.c
└── test
    ├── CMakeLists.txt
    ├── homework_tests
    │   ├── CMakeLists.txt
    │   ├── gtest.cpp
    │   └── gtest.h
    └── lib
        └──googletest
            └──googletest
                └──[library files (not compiled)]

main.c 文件里面只有一个“Hello, world”。 阅读之前: 我正在尝试:
1. 从源文件构建目标src.so
2.构建谷歌测试库(在test/lib/文件夹中)
3. 从tests/ 文件夹构建目标runBasicTests
4. 将它们联系在一起

我承认我不是 CMake 大师,所以请注意这一点。

文件

现在,假设我们在项目根.

./

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(c_homework)

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -std=c11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(SOURCE_FILES
        main.c)

add_executable(homework_run ${SOURCE_FILES})

add_subdirectory(src)
add_subdirectory(test)

target_link_libraries(homework_run src.so)

src/:

CMakeLists.txt

set(SOURCE_FILES
        game/game.c)

add_library(src.so ${SOURCE_FILES})

target_include_directories (src.so PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

游戏/game.h

#ifndef C_HOMEWORK_GAME_H
#define C_HOMEWORK_GAME_H

#include <stdbool.h>

struct game_t {
    int id, price;
    const char *country_code;
};

bool is_game_available(struct game_t, const char[4]);
int how_many_available(struct game_t*, size_t, const char[4]);

#endif //C_HOMEWORK_GAME_H

游戏/game.c

#include <string.h>
#include "game.h"

bool is_game_available(struct game_t game, const char country_code[4]) 
{
    return strcmp(game.country_code, country_code) == 0;
}

int how_many_available(struct game_t * games, size_t game_count, const 
char country_code[4]) {
    int available_games = 0;
    for (int i = 0; i < game_count; i++) {
        if (is_game_available(games[i], country_code)) {
            available_games++;
        }
    }
    return available_games;
}

test/:

CMakeLists.txt

project(homework_tests)

add_subdirectory(lib/googletest/googletest)
add_subdirectory(homework_tests)

homework_tests/CMakeLists.txt

include_directories(${gTest_SOURCE_DIR}/include ${gTest_SOURCE_DIR})

add_executable(runBasicTests
        gtest.cpp)

target_link_libraries(runBasicTests gtest gtest_main)
target_link_libraries(runBasicTests src.so)

homework_tests/gtest.cpp

#include "gtest.h"
#include <game/game.h>

int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

TEST(gameTests, gameTest1) {
    struct game_t game{};
    game.country_code = "359";
    game.id = 1;
    game.price = 69;
    EXPECT_EQ(is_game_available(game, "359"), true);
}

homework_tests/gtest.h

#ifndef MYPROJECTNAME_GTEST_H
#define MYPROJECTNAME_GTEST_H

#include "gtest/gtest.h"

#endif //MYPROJECTNAME_GTEST_H

问题是,当我尝试运行测试时,我收到 linker 错误:

/opt/clion-2018.1/bin/cmake/bin/cmake --build 
/home/denis/CLionProjects/c_homework/cmake-build-debug --target 
runBasicTests -- -j 1

[ 25%] Built target gtest
Scanning dependencies of target src.so
[ 37%] Building C object src/CMakeFiles/src.so.dir/game/game.c.o
[ 50%] Linking C static library libsrc.so.a
[ 50%] **Built target src.so**
[ 75%] Built target gtest_main
[ 87%] Linking CXX executable runBasicTests
CMakeFiles/runBasicTests.dir/gtest.cpp.o: In function 
`gameTests_gameTest1_Test::TestBody()':
/home/denis/CLionProjects/c_homework/test/homework_tests/gtest.cpp:18:

          <---------------   Here   ----------------->   
undefined reference to `is_game_available(game_t, char const*)'
collect2: error: ld returned 1 exit status

test/homework_tests/CMakeFiles/runBasicTests.dir/build.make:98: recipe 
for target 'test/homework_tests/runBasicTests' failed
make[3]: *** [test/homework_tests/runBasicTests] Error 1
CMakeFiles/Makefile2:294: recipe for target 
'test/homework_tests/CMakeFiles/runBasicTests.dir/all' failed
make[2]: *** [test/homework_tests/CMakeFiles/runBasicTests.dir/all] 
Error 2
CMakeFiles/Makefile2:306: recipe for target 
'test/homework_tests/CMakeFiles/runBasicTests.dir/rule' failed
make[1]: *** [test/homework_tests/CMakeFiles/runBasicTests.dir/rule] 
Error 2
Makefile:170: recipe for target 'runBasicTests' failed
make: *** [runBasicTests] Error 2
  • 不需要我的库的测试可以正常运行
  • src/ 文件夹中并与src.so 库链接的目标也可以正确运行

【问题讨论】:

  • 这可能与源代码写在 C 和测试 - 在 C++ 中的事实有关
  • 不会可能与那个事实有关。您的 game.h 头文件需要确定它是否正在由 C 或 C++ 编译器编译(提示:__cplusplus 宏对此很有用),如果在 C++ 中,则使用 extern "C" 禁用名称修改。跨度>
  • 你的情况是这个:*.com/questions/12573816/…
  • Yesssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss!

标签: c cmake linker googletest


【解决方案1】:

问题是我正在从 C++ 代码调用 C 代码,而 C++ 编译器正在更改函数的名称(名称修改),这就是我收到 undefined reference 错误的原因。

解决方案是告诉编译器以下函数声明是外部“C”代码。

test/homework_tests/gtest

#ifdef __cplusplus
extern "C" {
#endif
    /* Declarations of this file */
    bool is_game_available(struct game_t, const char[4]);
    int how_many_available(struct game_t *, size_t, const char[4]);
#ifdef __cplusplus
}
#endif

这解决了问题。谢谢大家。呵呵

【讨论】: