我正在制作一个库,它将定义许多函数。每个函数都会有一个默认版本,然后用户可以提供一个包含每个函数的替代定义的文件,并针对特定硬件目标进行优化。
我有一个头文件,例如
operations.h
:
//operations.h
#ifndef OPERATIONS_H
#define OPERATIONS_H
#define BASE_OPERATION_1
int operation_1(int a, int b);
#define BASE_OPERATION_2
int operation_2(int a, int b);
#endif
然后是源文件中的默认实现:
//base/operations.c
#ifdef BASE_OPERATION_1
int op_1(int a, int b)
{
return a + b;
}
#endif
#ifdef BASE_OPERATION_2
int op_2(int a, int b)
{
return 2 * (a + b);
}
#endif
然后我在单独的源文件中进行自定义实现。可能无法替代所有功能。
// custom/operations.c
#ifdef CUSTOM_OPERATION_2
#undef BASE_OPERATION_2
int op_2(int a, int b)
{
return 3 * (a + b);
}
#endif
然后在工具链文件中我可以做
set(CUSTOM_SOURCES custom/operations.c)
add_definitions( -DCUSTOM_OPERATION_2 )
上述解决方案会导致“重复符号”错误。我认为因为预处理器不会同时看到两个 .c 文件,所以
undef
没有实现我想要的行为。它们位于不同的翻译单元中,因此在编译基础文件时永远不会看到 undef。
谁能告诉我如何实现这种行为?
难道是这些源文件的编译顺序有关?如果首先编译基数,它将使用定义的 BASE_OPERATION_2 进行编译,这将导致重复符号。
您可以尝试更改 op1 和 op2 的操作,如下所示,然后重试:
#ifndef CUSTOM_OPERATION_2
#define BASE_OPERATION_2
#endif
要解决您的问题,请删除所有预处理器 有关
BASE_OPERATION_N
的指令并重写源文件,如下所示:
//operations.h
#ifndef OPERATIONS_H
#define OPERATIONS_H
int op_1(int a, int b);
int op_2(int a, int b);
#endif
//base/operations.c
#include <operations.h>
#ifndef CUSTOM_OP_1
int op_1(int a, int b)
{
return a + b;
}
#endif
#ifndef CUSTOM_OP_2
int op_2(int a, int b)
{
return 2 * (a + b);
}
#endif
// custom/operations.c
#ifdef CUSTOM_OP_2
int op_2(int a, int b)
{
return 3 * (a + b);
}
#endif
有了这个,
-DCUSTOM_OP_2
足以禁用基础op_2
的编译和
启用自定义op_2
的编译。相反,缺少 -DCUSTOM_OP_2
足以禁用自定义 op_2
的编译并启用编译
底座 op_2
.
这是一个演示。我的 CMake 项目是:
$ tree
.
├── base
│ └── operations.c
├── CMakeLists.txt
├── config.cmake
├── custom
│ └── operations.c
├── operations.h
└── test.c
cmake.config
是我的工具链文件。它不需要存在
默认构建。我正在构建一个测试程序和库来证明这是有效的。为了
出于同样的目的,我在来源中添加了一些printf
:
$ cat base/operations.c
//base/operations.c
#include <stdio.h>
#include <operations.h>
#ifndef CUSTOM_OP_1
int op_1(int a, int b)
{
printf("%s_%s\n","Base",__func__);
return a + b;
}
#endif
#ifndef CUSTOM_OP_2
int op_2(int a, int b)
{
printf("%s_%s\n","Base",__func__);
return 2 * (a + b);
}
#endif
$ cat custom/operations.c
// custom/operations.c
#include <stdio.h>
#ifdef CUSTOM_OP_1
int op_1(int a, int b)
{
printf("%s_%s\n","Custom",__func__);
return 3 * (a + b);
}
#endif
#ifdef CUSTOM_OP_2
int op_2(int a, int b)
{
printf("%s_%s\n","Custom",__func__);
return 3 * (a + b);
}
#endif
我的
CMakeLists.txt
是:
$ cat CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(operations)
set(BASE_SOURCES ./base/operations.c)
set(SOURCES ${BASE_SOURCES} ${CUSTOM_SOURCES})
include_directories(./)
add_library(
operations
${SOURCES}
)
add_executable(
test
test.c)
target_link_libraries(test operations)
默认构建是:
$ mkdir build
$ cd build
$ cmake ..
-- The C compiler identification is GNU 13.2.0
-- The CXX compiler identification is GNU 13.2.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 (0.2s)
-- Generating done (0.0s)
-- Build files have been written to: /home/imk/develop/so/cmake_prob/build
$ make
[ 25%] Building C object CMakeFiles/operations.dir/base/operations.c.o
[ 50%] Linking C static library liboperations.a
[ 50%] Built target operations
[ 75%] Building C object CMakeFiles/test.dir/test.c.o
[100%] Linking C executable test
[100%] Built target test
程序运行:
$ ./test
Base_op_1
Base_op_2
现在这是我的工具链文件 v.1:
$ cd ..
$ cat config.cmake
set(CUSTOM_SOURCES ./custom/operations.c)
add_compile_options(-DCUSTOM_OP_2)
我正在禁用基础
op_2
,启用自定义 op_2
Zap 并重新生成构建系统:
$ cd build
$ rm -fr *
$ cmake -DCMAKE_TOOLCHAIN_FILE=config.cmake ..
-- The C compiler identification is GNU 13.2.0
-- The CXX compiler identification is GNU 13.2.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 (0.2s)
-- Generating done (0.0s)
-- Build files have been written to: /home/imk/develop/so/cmake_prob/build
重建并测试:
$ make && ./test
[ 20%] Building C object CMakeFiles/operations.dir/base/operations.c.o
[ 40%] Building C object CMakeFiles/operations.dir/custom/operations.c.o
[ 60%] Linking C static library liboperations.a
[ 60%] Built target operations
[ 80%] Building C object CMakeFiles/test.dir/test.c.o
[100%] Linking C executable test
[100%] Built target test
Base_op_1
Custom_op_2
有定制
op_2
。
现在我想恢复到基本
op_2
并启用自定义 op_1
。其工具链文件是 v.2:
$ cd ..
$ cat config.cmake
set(CUSTOM_SOURCES ./custom/operations.c)
add_compile_options(-DCUSTOM_OP_1)
现在不需要重新生成构建系统。我能做到:
$ cd build
$ make
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/imk/develop/so/cmake_prob/build
[ 20%] Building C object CMakeFiles/operations.dir/base/operations.c.o
[ 40%] Building C object CMakeFiles/operations.dir/custom/operations.c.o
[ 60%] Linking C static library liboperations.a
[ 60%] Built target operations
[ 80%] Building C object CMakeFiles/test.dir/test.c.o
[100%] Linking C executable test
[100%] Built target test
$ ./test
Custom_op_1
Base_op_2
有定制
op_1
。