简体   繁体   English

将具有循环链接依赖关系的makefile转换为CMake

[英]Converting makefile with circular link dependency to CMake

I have multiple implementations(.c or .cpp files) that implements different function of the same header file. 我有多个实现(.c或.cpp文件),可实现同一头文件的不同功能。 I have the makefile approach for build and I want to reimplement it with cmake.(Note that I cannot change the implementation files or headers. If I could, I wouldn't design and implement the solution as it is.) I have prepared smaller case to point out my issue. 我有用于make的makefile方法,我想用cmake重新实现它。(请注意,我无法更改实现文件或标头。如果可以的话,我不会按原样设计和实现该解决方案。)案例来指出我的问题。

head.h: head.h:

#ifndef __HEAD__
#define __HEAD__

int foo(float e, float b);
void boo(float *eo, float *eh);
void setup();
int load(int* n);

#endif

impl1.c: impl1.c:

#include "head.h"

void boo(float *eo, float *eh)
{
  *eo = 0.4f;
  *eh = 2.3f;
}

impl2.c: impl2.c:

#include <stdio.h>
#include "head.h"
void setup()
{
  printf("hello!\n");
  int m = 13;
  int* n = &m;
  load(n);
}

impl3.c: impl3.c:

#include "head.h"
int load(int* n)
{
  n = 0;
  return 0;
}

main.cpp: main.cpp:

#include "head.h"
int main()
{
  setup();
  return 0;
}
int foo(float e, float b)
{
  float i, j;
  boo(&i, &j);
  return 4;
}

makefile:(this is building and linking) makefile :(这是构建和链接)

# C compiler
CC = g++
CC_FLAGS = -g -O2

main: impl1.o impl2.o impl3.o
    $(CC) $(CC_FLAGS) main.cpp impl1.o impl2.o impl3.o -o main

%.o: %.[ch]
    $(CC) $(CC_FLAGS) $< -c

impl1.o: impl1.c
    $(CC) $(CC_FLAGS) impl1.c -c

impl2.o: impl2.c
    $(CC) $(CC_FLAGS) impl2.c -c

impl3.o: impl3.c
    $(CC) $(CC_FLAGS) impl3.c -c

clean:
    rm -f *.o *~ main *.linkinfo

With the makefile, these commands are executed: 使用makefile,将执行以下命令:

g++ -g -O2 impl1.c -c
g++ -g -O2 impl2.c -c
g++ -g -O2 impl3.c -c
g++ -g -O2 main.cpp impl1.o impl2.o impl3.o -o main

What I have tried with cmake up to now:(you can observe my failed attempts as commented) 到目前为止,我使用cmake所做的尝试:(您可以观察到我的失败尝试已得到评论)

add_executable(${PROJECT_NAME} impl1.c impl2.c impl3.c main.cpp)

# add_library(impl1 OBJECT impl1.c)
# add_library(impl2 OBJECT impl2.c)
# add_library(impl3 OBJECT impl3.c)
# add_executable(${PROJECT_NAME} main.cpp $<TARGET_OBJECTS:impl3> $<TARGET_OBJECTS:impl2> $<TARGET_OBJECTS:impl1>)

# add_library(impl1 STATIC impl1.c)
# add_library(impl2 STATIC impl2.c)
# add_library(impl3 STATIC impl3.c)
# add_executable(main main.cpp)
#
# set(LIBS impl1 impl2 impl3)
#
# target_link_libraries(main ${LIBS} ${LIBS})

# add_library(headextra impl1.c impl2.c impl3.c)
# add_executable(${PROJECT_NAME} main.cpp)
# target_link_libraries(${PROJECT_NAME} headextra)

# add_library(headextra impl1.c impl2.c impl3.c main.cpp)
# add_executable(${PROJECT_NAME} $<TARGET_OBJECTS:headextra>)

This cmake file successfully generates the build and also compiles. 该cmake文件成功生成了构建并进行了编译。 But when linking I got errors that I couldn't resolve: 但是在链接时出现无法解决的错误:

make -f CMakeFiles/cmake_test.dir/build.make CMakeFiles/cmake_test.dir/build
/usr/bin/cc    -o CMakeFiles/cmake_test.dir/impl1.c.o   -c /home/ahmet/Desktop/cmake_test/impl1.c
/usr/bin/cc    -o CMakeFiles/cmake_test.dir/impl2.c.o   -c /home/ahmet/Desktop/cmake_test/impl2.c
/usr/bin/cc    -o CMakeFiles/cmake_test.dir/impl3.c.o   -c /home/ahmet/Desktop/cmake_test/impl3.c
/usr/bin/c++     -o CMakeFiles/cmake_test.dir/main.cpp.o -c /home/ahmet/Desktop/cmake_test/main.cpp
/usr/bin/cmake -E cmake_link_script CMakeFiles/cmake_test.dir/link.txt --verbose=1
/usr/bin/c++      CMakeFiles/cmake_test.dir/impl1.c.o CMakeFiles/cmake_test.dir/impl2.c.o CMakeFiles/cmake_test.dir/impl3.c.o CMakeFiles/cmake_test.dir/main.cpp.o  -o cmake_test -rdynamic 
CMakeFiles/cmake_test.dir/main.cpp.o: In function `main':
main.cpp:(.text+0x5): undefined reference to `setup()'
CMakeFiles/cmake_test.dir/main.cpp.o: In function `foo(float, float)':
main.cpp:(.text+0x31): undefined reference to `boo(float*, float*)'
collect2: error: ld returned 1 exit status
make[2]: *** [cmake_test] Error 1
make[1]: *** [CMakeFiles/cmake_test.dir/all] Error 2
make: *** [all] Error 

I am definitely missing some key point about cmake build generation. 我肯定缺少有关cmake构建生成的一些关键点。 Hopefully, some can help. 希望能有所帮助。

That should not work even in the old Makefile, since you are mixing C and C++. 即使在旧的Makefile中,这也不起作用,因为您正在混合使用C和C ++。 The problem is actually unrelated to your build-system and have to do just with the mixing of C and C++. 该问题实际上与您的构建系统无关,并且仅与C和C ++的混合有关。

To solve it change the header files as: 要解决该问题,请将头文件更改为:

#ifndef HEAD_H
#define HEAD_H

#ifdef __cplusplus
extern "C" {
#endif

int foo(float e, float b);
void boo(float *eo, float *eh);
void setup();
int load(int* n);

#ifdef __cplusplus
}
#endif

#endif

The big change is that in the header file I have added a check for the macro __cplusplus which will be defined by a C++ compiler and not a C compiler. 最大的变化是,在头文件中,我添加了对__cplusplus宏的检查,该检查将由C ++编译器而不是C编译器定义。 When __cplusplus is defined, I have told the compiler to treat the function declarations as "C" declarations, which means there will be no name mangling done for the functions. 定义__cplusplus ,我已告诉编译器将函数声明视为“ C”声明,这意味着将不对函数进行名称处理

The problem is that the C++ compiler mangles its function names, to enable function overloading. 问题是,C ++编译器轧液的函数名,以使函数重载。 And that means the symbol for eg the function setup is something different when compiling as C++. 这就意味着在编译为C ++时,例如功能setup的符号有所不同。 The extern "C" tells the C++ compiler to not mangle the names. extern "C"告诉C ++编译器不要弄乱名称。

See eg this reference for more information about extern "C" . 请参阅此参考资料 ,以获取有关extern "C"更多信息。

Also note that I changed the header include guards, as all symbols with double leading underscores are reserved for the "implementation" (ie the compiler and standard library) in all scopes. 还要注意,我更改了标头包括防护,因为在所有作用域中,所有带有双引号下划线的符号都保留用于“实现”(即编译器和标准库)。 See eg this old question and answer . 参见例如这个古老的问答

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM