根据工具链文件中的定义替换单个函数定义

问题描述 投票:0回答:2

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

我有一个头文件,例如

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。

谁能告诉我如何实现这种行为?

c cmake linker
2个回答
1
投票

难道是这些源文件的编译顺序有关?如果首先编译基数,它将使用定义的 BASE_OPERATION_2 进行编译,这将导致重复符号。

您可以尝试更改 op1 和 op2 的操作,如下所示,然后重试:

#ifndef CUSTOM_OPERATION_2
#define BASE_OPERATION_2
#endif 

0
投票

要解决您的问题,请删除所有预处理器 有关

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

© www.soinside.com 2019 - 2024. All rights reserved.