2016-08-02 18 views
0

Ich habe mehrere Implementierungen (.c oder .cpp-Dateien), die verschiedene Funktionen der gleichen Header-Datei implementiert. Ich habe den Makefile Ansatz für Build und ich möchte es mit cmake neu implementieren. (Beachten Sie, dass ich die Implementierungsdateien oder Header nicht ändern kann. Wenn ich könnte, würde ich die Lösung nicht so entwerfen und implementieren wie sie ist.) Ich habe kleinere vorbereitet Fall, um auf mein Problem hinzuweisen.Konvertieren von Makefile mit Circular Link-Abhängigkeit zu CMake

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:

#include "head.h" 

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

impl2.c:

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

impl3.c:

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

main.cpp:

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

Make-Datei: (dies baut und zum Verlinken)

# 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 

Mit dem Make-Datei, werden diese Befehle ausgeführt:

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 

Was habe ich versucht, mit cmake bis jetzt: (Sie können meine fehlgeschlagenen Versuche als kommentiert beobachten)

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>) 

Diese CMake-Datei generiert erfolgreich den Build und kompiliert sie auch. Aber beim Verknüpfen habe ich Fehler bekommen, die ich nicht beheben konnte:

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 

Ich vermisse definitiv einen wichtigen Punkt über CMake Build Generation. Hoffentlich können einige helfen.

Antwort

3

Das sollte nicht einmal im alten Makefile funktionieren, da Sie C und C++ mischen. Das Problem steht in keinem Zusammenhang mit Ihrem Build-System und muss nur mit dem Mischen von C und C++ geschehen.

Um es zu lösen, die Header-Dateien wie zu ändern:

Die große Veränderung, dass ich einen Scheck für das Makro __cplusplus habe in der Header-Datei ist
#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 

hinzugefügt, die von einem C++ Compiler und kein C definiert werden Compiler. Wenn __cplusplus definiert ist, habe ich den Compiler angewiesen, die Funktionsdeklarationen als "C" -Deklarationen zu behandeln, was bedeutet, dass name mangling für die Funktionen nicht ausgeführt wird.

Das Problem ist, dass der C++ - Compiler seine Funktionsnamen manipuliert, um Funktion Überladung zu ermöglichen. Und das bedeutet das Symbol für z.B. Die Funktion setup ist etwas anders beim Kompilieren als C++. Die extern "C" teilt dem C++ - Compiler mit, die Namen nicht zu verändern.

Siehe z.B. this reference für weitere Informationen über extern "C".

Beachten Sie auch, dass ich die Header-Include-Wächter geändert habe, da alle Symbole mit doppelt führenden Unterstrichen für die "Implementierung" (d. H. Den Compiler und die Standardbibliothek) in allen Bereichen reserviert sind. Siehe z.B. this old question and answer.

+1

Ich denke, es hat funktioniert, weil er 'CC = g ++' so definiert, dass der C++ - Compiler zum Kompilieren von C-Code verwendet wird. – Jens

+0

Vielen Dank für Ihre klare Antwort. Es funktionierte. Auch für den Hinweis auf doppelte führende Unterstreichungen habe ich das vergessen. – Vemulo

Verwandte Themen