我正在制作一个库,它将定义许多功能.每个功能都有一个默认版本,然后用户可以提供一个包含每个功能的替代定义的文件,该定义针对特定硬件目标进行了优化.

我有一个头文件例如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没有实现我想要的行为.它们位于不同的翻译单元中,因此在编译基本文件时永远不会看到unef.

有人能告诉我如何获得这种行为吗?

推荐答案

要解决您的问题,请删除所有预处理器 有关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)

我正在禁用Base op_2,启用自定义op_2

激活并重新生成构建系统:

$ 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.

C++相关问答推荐

为什么这个gcc迂腐的人忽视了扩展?

如何避免使用相对路径包含在c中

如何将FileFilter添加到FileDialog GTK 4

无效使用未定义类型'structsquare'?

为什么我得到更多的256假阳性在PKZIP解密密钥验证?

在C++中使用函数指针的正确语法

VS代码';S C/C++扩展称C23真关键字和假关键字未定义

加密解密工作正常,但返回错误0x80090005

Vcpkg的配置文件

S的这种管道实施有什么问题吗?

如何计算打印二叉搜索树时每行所需的空间?

tick.q中的Kdb+键控表语法

Boyer Moore算法的简单版本中的未定义行为

处理EPOLL_WAIT中的接收数据和连接关闭信号

在进程之间重定向输出和输入流的问题

链接到底是如何工作的,我在这里到底做错了什么

覆盖读取函数,但当文件描述符为3或4时,我有问题

c程序,让用户输入两类数字,并给出输出用户输入多少个数字

struct 中的qsort,但排序后的 struct 很乱

C 错误:对 int 数组使用 typedef 时出现不兼容的指针类型问题