习惯了使用cmake,再也不想回到手写makefile的年代了。相比手写makefile,使用cmake则像是实现了机动化,管理项目工程的编译变得很简单了。况且cmake很流行,linux下的很多软件源码包,很多也都使用了cmake的方式编译。因此这里总结下嵌入式linux环境下如何使用cmake,以及嵌入式qt的cmake配置。
CMake简介
什么是CMake
你或许听过好几种 Make 工具,例如 GNU Make ,QT 的 qmake ,微软的 MS nmake,BSD Make(pmake),Makepp,等等。这些 Make 工具遵循着不同的规范和标准,所执行的 Makefile 格式也千差万别。这样就带来了一个严峻的问题:如果软件想跨平台,必须要保证能够在不同平台编译。而如果使用上面的 Make 工具,就得为每一种标准写一次 Makefile ,这将是一件让人抓狂的工作,手写makefile也不是个很容易的事。
CMake就是针对上面问题所设计的工具:它首先允许开发者编写一种平台无关的 CMakeList.txt 文件来定制整个编译流程,然后再根据目标用户的平台进一步生成所需的本地化 Makefile 和工程文件,如 Unix 的 Makefile 或 Windows 的 Visual Studio 工程。从而做到“Write once, run everywhere”。显然,CMake 是一个比上述几种 make 更高级的编译配置工具。一些使用 CMake 作为项目架构系统的知名开源项目有 VTK、ITK、KDE、OpenCV、OSG 等 。
在 linux 平台下使用 CMake 生成 Makefile 并编译的流程如下:
1、编写 CMake 配置文件 CMakeLists.txt 。
2、执行命令 cmake PATH 或者 ccmake PATH 生成 Makefile(ccmake
和 cmake
的区别在于前者提供了一个交互式的界面),其中 PATH
是 CMakeLists.txt 所在的目录。
3、使用 make 命令进行编译。
cmake安装
Download | CMake
linux下的cmake安装很简单。以ubuntu为例,可以直接sudo apt-get install cmake。当然也可以手工下载最新源码包来安装。这里选择了一种最简单的方式。
sudo apt-get install cmake
cmake交叉编译环境下的配置
指定cmake使用的交叉编译工具链(选项:DCMAKE_TOOLCHAIN_FILE)。
在项目根目录下新建个toolchains目录,在此目录下,参照其它开发板的配置文件,添加一个该开发板的配置文件arm-poky-linux-gnueabi.cmake。
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER "arm-poky-linux-gnueabi-gcc")
set(CMAKE_CXX_COMPILER "arm-poky-linux-gnueabi-g++")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)set(CMAKE_C_FLAGS "-march=armv7-a -mfloat-abi=hard -mfpu=neon --sysroot=/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/cortexa7hf-neon-poky-linux-gnueabi")
set(CMAKE_CXX_FLAGS "-march=armv7-a -mfloat-abi=hard -mfpu=neon --sysroot=/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/cortexa7hf-neon-poky-linux-gnueabi")# cache flags
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "c flags")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" CACHE STRING "c++ flags")
cmake使用
新建个cmake_test项目文件夹,内部新建hello.c文件源码。
#include <stdio.h>int main(){printf("hello world\n");return 0;
}
编写CMakeLists.txt文件,注释掉的内容可以不用管,其实内容很少。
cmake_minimum_required(VERSION 3.12)project(HELLO)#add_definitions(# -D_ENABLE_LOGGING
#)set(SRC_LIST hello.c)#add library(libhello SHARED hello.c)
#set_target_properties(libhello PROPERTIES OUTPUT NAME "hello")
add_executable(hello ${SRC_LIST})
#target_link_libraries(hello libhello)
开始编译
在项目根目录下创建build目录,然后cd build,先进入build目录。注意,需要指定-DCMAKE_TOOLCHAIN_FILE。
#先加载环境变量
source /opt/fsl-imx-x11/4.1.15-2.1.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi #在项目根目录,cd build,先进入build目录
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../toolchains/arm-poky-linux-gnueabi.cmake ../
最终生成了可以在板子上执行的可执行文件。
QT交叉编译环境下的cmake脚本
示例demo,main.cpp:
#include <QCoreApplication>
#include<QDebug>
#include <QDir>int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);qDebug() << "hello QT test";return a.exec();
}
QT项目的交叉编译环境下的cmake脚本:
cmake_minimum_required(VERSION 3.12)project(helloqt)add_definitions(-D_ENABLE_LOGGING
)#set(CMAKE_PREFIX_PATH "/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/cortexa7hf-neon-poky-linux-gnueabi/usr/lib/cmake")set(BUILD_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build_out)
get_filename_component(ABSOLUTE_PATH ${BUILD_DIRECTORY} ABSOLUTE)
set(BUILD_DIRECTORY ${ABSOLUTE_PATH})#################### QT dependencies ####################
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)set(QT_VERSION 5)
set(CMAKE_CROSSCOMPILING TRUE)
set(OE_QMAKE_PATH_EXTERNAL_HOST_BINS /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/bin)set(REQUIRED_LIBS Core Quick Widgets)
set(REQUIRED_LIBS_QUALIFIED Qt5::Core Qt5::Quick Qt5::Widgets)#################### set output directory ####################
set(BUILD_DIR ${BUILD_DIRECTORY})
set(LIB_DIR ${BUILD_DIR}/lib/Release)
#set(LIB_FIX)
#if (CMAKE_BUILD_TYPE MATCHES "Debug")
# set(LIB_DIR ${BUILD_DIR}/lib/Debug)
# set(LIB_FIX _d)
#endif ()#get_filename_component(ABSOLUTE_PATH ${LIB_DIR} ABSOLUTE)
#set(LIB_DIR ${ABSOLUTE_PATH})set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIB_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIB_DIR})
set(CMAKE_PDB_OUTPUT_DIRECTORY ${LIB_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIB_DIR})#set(LIB_DIR_FIX ${LIB_DIR})
#option(USE_VS_BUILD "use visual studio build." OFF)
#if (USE_VS_BUILD)
# set(LIB_DIR_FIX ${LIB_DIR}/bin/Debug)
#endif ()
###########set include path ####################
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/${BUILD_DIR}/include
)#################### scan source files ####################
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/ SRC_FILES)
#aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/source/cpp/test2 SRC_FILES)#set(SRC_LIST hello.c)#add library(libhello SHARED hello.c)
#set_target_properties(libhello PROPERTIES OUTPUT NAME "hello")
find_package(Qt${QT_VERSION} COMPONENTS ${REQUIRED_LIBS} REQUIRED)
#find_package(Qt5 COMPONENTS Widgets)add_executable(${PROJECT_NAME} ${SRC_FILES})
#target_link_libraries(hello libhello)#################### set target dependencies ####################set(THIRD_LIBS "")target_link_libraries(${PROJECT_NAME} PRIVATE ${REQUIRED_LIBS_QUALIFIED} ${THIRD_LIBS})
报错信息
报错解决办法
根据错误提示,提示表明在CMake中找不到OE_QMAKE_PATH_EXTERNAL_HOST_BINS变量。这是因为您的交叉编译环境中没有设置正确的OpenEmbedded(OE)环境变量。
可以在CMakeLists.txt文件中添加以下行来设置OE_QMAKE_PATH_EXTERNAL_HOST_BINS变量。它的目的是为了找到qmake的位置。因此可以设置如下:
set(QT_VERSION 5)
set(CMAKE_CROSSCOMPILING TRUE)
set(OE_QMAKE_PATH_EXTERNAL_HOST_BINS /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/bin)
开始编译
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../toolchains/arm-poky-linux-gnueabi.cmake -DCMAKE_PREFIX_PATH=/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/cortexa7hf-neon-poky-linux-gnueabi/usr/lib/cmake ../
如果嫌上面这串命令有点儿长,可以把-DCMAKE_PREFIX_PATH写固定到CMakeLists.txt文件里。如下(带不带""都行):
set(CMAKE_PREFIX_PATH "/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/cortexa7hf-neon-poky-linux-gnueabi/usr/lib/cmake")
最后,编译成功啦!终于可以在嵌入式环境下愉快的使用cmake来编译qt的工程。如果不想安装使用qtcreater这个庞大IDE的话。或者想使用脚本的方式编译qt项目,使用cmake是个不错的选择。
经过以上操作,成功生成helloqt可执行文件。把该文件放置到开发板上,可以看到执行效果。生成的可执行文件的位置在build_out/lib/Release/路径下。
其他资源
https://m.elecfans.com/article/2012326.html
CMAKE介绍和使用(Linux平台)_cmake linux_L888666Q的博客-CSDN博客
【cmake实战一】linux下安装cmake的两个方法_cmake安装_郑同学的笔记的博客-CSDN博客
cmake超详细入门教程_cmake编译流程_yygr的博客-CSDN博客
利用VSCode+cmake+GDB+gdbserver调试IMX6ULL的Linux C应用程序_imx6ull cmake_生啃枸杞的博客-CSDN博客