1 问题现象
用c语言写了个lib ,编译成了动态链接库,然后建了一个QT项目,想调用自己编写的lib里面的函数,编译的时候发现build OK,但是link的时候error,找不到lib 里面的函数。
[ 20%] Automatic MOC and UIC for target gst_player
[ 20%] Built target gst_player_autogen
[ 40%] Linking CXX executable gst_player
CMakeFiles/gst_player.dir/main.cpp.o: In function `main':
main.cpp:(.text+0x52): undefined reference to `Start_Play(char*)'
main.cpp:(.text+0x89): undefined reference to `Stop_Play()'
collect2: error: ld returned 1 exit status
CMakeFiles/gst_player.dir/build.make:154: recipe for target 'gst_player' failed
make[2]: *** [gst_player] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/gst_player.dir/all' failed
make[1]: *** [CMakeFiles/gst_player.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
lib的名称是mmplayer,lib的头文件里已经声明了这两个接口,QT项目中也引入了这个头文件:
int Start_Play(char *path);
int Stop_Play(void);
QT项目构建方式选择了cmake,cmake中通过link_directories和include_directories直接设置库文件和头文件的地址。
include_directories(${PROJECT_SOURCE_DIR})
link_directories(${PROJECT_SOURCE_DIR})
find_library (libpath mmplayer ${PROJECT_SOURCE_DIR})
if (${libpath} STREQUAL "libpath-NOTFOUND")
message (STATUS "required mmplayer library but not found!")
else()
message (STATUS "libpath library found in ${libpath}")
endif()
add_executable(gst_player
main.cpp
mainwindow.cpp
mainwindow.h
mainwindow.ui
)
message(${PROJECT_SOURCE_DIR}/libs/)
target_link_libraries(gst_player PRIVATE Qt5::Widgets mmplayer)
2 问题原因及解决方案
一开始以为是路径设置不对,但是find_library也可以找到这个lib,但是就是链接不到。
zhy@zhy-ThinkPad-E480:~/code/mypc/blog_code/gst_player/qt_gst_player/gst_player$ cmake ./
...
-- libpath library found in /home/zhy/code/mypc/blog_code/gst_player/qt_gst_player/gst_player/libs/libmmplayer.so
-- Configuring done
-- Generating done
-- Build files have been written to: /home/zhy/code/mypc/blog_code/gst_player/qt_gst_player/gst_player
于是用c写了一个程序来调用这个lib,main.c中的内容:
#include <mediaPlayer.h>
int main()
{
int ret = 0;
char *filePath = "https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_cropped_multilingual.webm";
ret = Start_Play(filePath);
if (ret != 0)
{
return - 1;
}
//play 50s
sleep(50);
ret = Stop_Play();
if (ret != 0)
{
return - 1;
}
return 0;
}
make文件:
cmake_minimum_required(VERSION 3.5)
project(camke_test LANGUAGES C)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include_directories(${PROJECT_SOURCE_DIR}) # 头文件的路径
link_directories(${PROJECT_SOURCE_DIR})
find_library (libpath mmplayer ${PROJECT_SOURCE_DIR})
if (${libpath} STREQUAL "libpath-NOTFOUND")
message (STATUS "required mmplayer library but not found!")
else()
message (STATUS "libpath library found in ${libpath}")
endif()
add_executable(camke_test
main.c
)
message(${PROJECT_SOURCE_DIR}/libs/)
target_link_libraries(camke_test PRIVATE mmplayer)
然后编译,发现link也OK,说明了camke 里的so 链接没有问题。
zhy@zhy-ThinkPad-E480:~/code/mypc/blog_code/gst_player/cmake_test$ make
[ 50%] Building C object CMakeFiles/camke_test.dir/main.c.o
/home/zhy/code/mypc/blog_code/gst_player/cmake_test/main.c: In function ‘main’:
/home/zhy/code/mypc/blog_code/gst_player/cmake_test/main.c:17:5: warning: implicit declaration of function ‘sleep’ [-Wimplicit-function-declaration]
sleep(50);
^~~~~
[100%] Linking C executable camke_test
[100%] Built target camke_test
折腾了一晚上,后来搜索发现是C++调用C存在混编问题,详细原因可自行在网上百度。解决方案很简单,QT中引入用c编写的lib的头文件时用extern "C"来包含。
extern "C"
{
#include <mediaPlayer.h>
}
这样作的作用是告诉编译器,在编译C++的时候被调用的C代码仍然使用C编译选项,然后QT工程就可以顺利的编译通过了。
[ 20%] Automatic MOC and UIC for target gst_player
[ 20%] Built target gst_player_autogen
Scanning dependencies of target gst_player
[ 40%] Building CXX object CMakeFiles/gst_player.dir/main.cpp.o
[ 60%] Linking CXX executable gst_player
[100%] Built target gst_player
3 参考文章
https://blog.youkuaiyun.com/weixin_38956024/article/details/112549395