本文目标
- 使用自己写的动态库
- 使用第三方库
- 更新
cm
使用自己的动态库
写一个简单的库
目录结构
F:\2023\code\cmake\calc>tree /f
卷 dox 的文件夹 PATH 列表
卷序列号为 34D2-6BE8
F:.
│ CMakeLists.txt
│
├─include
│ └─calc
│ calc.h
│
└─src
calc.cpp
CMakeLists.txt
F:\2023\code\cmake\calc>
源码
include/calc/calc.h
#ifndef _CALC_H_
#define _CALC_H_
class Calc
{
public:
Calc();
~Calc();
int add(int a, int b);
};
#endif // _CALC_H_
src/calc.cpp
#include "calc/calc.h"
Calc::Calc()
{
}
Calc::~Calc()
{
}
int Calc::add(int a, int b)
{
return a + b;
}
CMakeLists.txt
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(calc CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_subdirectory(src)
src/CMakeLists.txt
include_directories(${PROJECT_SOURCE_DIR}/include)
aux_source_directory(. CALC_SRCS)
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
add_library(${PROJECT_NAME} SHARED ${CALC_SRCS})
set_target_properties(${PROJECT_NAME} PROPERTIES VERSION 1.0 SOVERSION 1)
生成动态库
F:\2023\code\cmake\calc>cmake -S . -G "Unix Makefiles" -B build && cmake --build build
-- The CXX compiler identification is GNU 10.3.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/program/tdmgcc/bin/g++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: F:/2023/code/cmake/calc/build
[ 50%] Building CXX object src/CMakeFiles/calc.dir/calc.cpp.obj
[100%] Linking CXX shared library F:/2023/code/cmake/calc/lib/libcalc.dll
[100%] Built target calc
F:\2023\code\cmake\calc>dir
驱动器 F 中的卷是 dox
卷的序列号是 34D2-6BE8
F:\2023\code\cmake\calc 的目录
2023/01/25 03:03 <DIR> .
2023/01/25 03:03 <DIR> ..
2023/01/25 03:03 <DIR> build
2023/01/25 02:57 150 CMakeLists.txt
2023/01/25 02:57 <DIR> include
2023/01/25 03:03 <DIR> lib
2023/01/25 02:58 <DIR> src
1 个文件 150 字节
6 个目录 91,635,671,040 可用字节
F:\2023\code\cmake\calc>cd lib
F:\2023\code\cmake\calc\lib>dir
驱动器 F 中的卷是 dox
卷的序列号是 34D2-6BE8
F:\2023\code\cmake\calc\lib 的目录
2023/01/25 03:03 <DIR> .
2023/01/25 03:03 <DIR> ..
2023/01/25 03:03 99,384 libcalc.dll
2023/01/25 03:03 3,844 libcalc.dll.a
2 个文件 103,228 字节
2 个目录 91,635,671,040 可用字节
F:\2023\code\cmake\calc\lib>
硬编码的方式使用
c++
#include <iostream>
#include <memory>
#include "calc/calc.h"
int main()
{
auto calc = std::make_unique<Calc>();
std::cout << "1 + 2 = " << calc->add(1,2) << std::endl;
std::cout << "hello world" << std::endl;
return 0;
}
CMakeLists.txt
# 该项目所需 cmake 的最小版本, 如果 cmake 版本小于设置的版本, cmake 将停止处理并报错
cmake_minimum_required(VERSION 3.0)
project(hello_cmake CXX)
set(CMAKE_BUILD_TYPE DEBUG)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# 检查是否定义了环境变量
if(NOT DEFINED ENV{calc_root})
message(FATAL_ERROR "not defined environment variable:calc_root")
endif()
# calc 根目录
set(calc_root_dir $ENV{calc_root})
# calc 库目录
set(calc_lib_dir ${calc_root_dir}/lib)
# calc 头文件目录
set(calc_include_dir ${calc_root_dir}/include)
# 连接库的头文件
include_directories(${calc_include_dir})
# 指定链接库目录
link_directories(${calc_lib_dir})
# 库名称
set(lib_calc_name calc)
# 库文件完整名称 windows 为 libcalc.dll , linux 为 libcalc.so
set(lib_calc_full_name ${CMAKE_SHARED_LIBRARY_PREFIX}calc${CMAKE_SHARED_LIBRARY_SUFFIX})
aux_source_directory(. MAIN_SRCS)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
add_executable(${PROJECT_NAME} ${MAIN_SRCS})
# 链接库文件
target_link_libraries(${PROJECT_NAME} ${lib_calc_name})
# 复制库文件,
# 只有 windows 下需要, 当然如果把 calc.dll 复制到系统目录倒也不用复制
if(${CMAKE_HOST_WIN32})
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${calc_lib_dir}/${lib_calc_full_name} ${PROJECT_SOURCE_DIR}/bin/${lib_calc_full_name})
endif()
windows 验证
F:\2023\code\cmake\hello_cmake>set calc_root=
F:\2023\code\cmake\hello_cmake>cmake -S . -G "Unix Makefiles" -B build && cmake --build build
CMake Error at CMakeLists.txt:12 (message):
not defined environment variable:calc_root
-- Configuring incomplete, errors occurred!
See also "F:/2023/code/cmake/hello_cmake/build/CMakeFiles/CMakeOutput.log".
F:\2023\code\cmake\hello_cmake>set calc_root=F:/2023/code/cmake/calc
F:\2023\code\cmake\hello_cmake>cmake -S . -G "Unix Makefiles" -B build && cmake --build build
-- Configuring done
-- Generating done
-- Build files have been written to: F:/2023/code/cmake/hello_cmake/build
[100%] Built target hello_cmake
F:\2023\code\cmake\hello_cmake>dir bin
驱动器 F 中的卷是 dox
卷的序列号是 34D2-6BE8
F:\2023\code\cmake\hello_cmake\bin 的目录
2023/01/25 04:08 <DIR> .
2023/01/25 04:08 <DIR> ..
2023/01/25 04:08 2,929,130 hello_cmake.exe
2023/01/25 04:08 99,384 libcalc.dll
2 个文件 3,028,514 字节
2 个目录 91,583,438,848 可用字节
F:\2023\code\cmake\hello_cmake>.\bin\hello_cmake.exe
1 + 2 = 3
hello world
F:\2023\code\cmake\hello_cmake>
linux 验证
ubuntu@ubuntu-cpp:~/code/cmake/hello_cmake$ unset calc_root
ubuntu@ubuntu-cpp:~/code/cmake/hello_cmake$ cmake -S . -B build && cmake --build build
CMake Error at CMakeLists.txt:12 (message):
not defined environment variable:calc_root
-- Configuring incomplete, errors occurred!
See also "/home/ubuntu/code/cmake/hello_cmake/build/CMakeFiles/CMakeOutput.log".
ubuntu@ubuntu-cpp:~/code/cmake/hello_cmake$ export calc_root=/home/ubuntu/code/cmake/calc
ubuntu@ubuntu-cpp:~/code/cmake/hello_cmake$ cmake -S . -B build && cmake --build build
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ubuntu/code/cmake/hello_cmake/build
[ 50%] Building CXX object CMakeFiles/hello_cmake.dir/main.cpp.o
[100%] Linking CXX executable /home/ubuntu/code/cmake/hello_cmake/bin/hello_cmake
[100%] Built target hello_cmake
ubuntu@ubuntu-cpp:~/code/cmake/hello_cmake$ ll bin
total 68
drwxrwxr-x 2 ubuntu ubuntu 4096 Jan 25 04:24 ./
drwxrwxr-x 4 ubuntu ubuntu 4096 Jan 25 04:24 ../
-rwxrwxr-x 1 ubuntu ubuntu 58440 Jan 25 04:24 hello_cmake*
ubuntu@ubuntu-cpp:~/code/cmake/hello_cmake$ ./bin/hello_cmake
1 + 2 = 3
hello world
ubuntu@ubuntu-cpp:~/code/cmake/hello_cmake$
find_package 的方式
其实上面的硬编码只是硬编码了 calc_root
这个变量, cmake 脚本在 windows 和 linux 已经是通用的了, 而且使用的时候有检查环境变量. 但是如果有好多个库要使用, 那么上面的方式就不太适用了. 此时可以用 find_package 来解决此问题
推荐参考:
cmake(三十二)Cmake之find_package指令
cmake(7):find_package命令详解
cmake教程4(find_package使用)
目录结构
ubuntu@ubuntu-cpp:~/code/cmake/hello_cmake$ tree -a
.
├── CMakeLists.txt
├── cmake
│ └── FindCALC.cmake
└── main.cpp
1 directory, 3 files
ubuntu@ubuntu-cpp:~/code/cmake/hello_cmake$
CMakeLists.txt
CMakeLists.txt
# 该项目所需 cmake 的最小版本, 如果 cmake 版本小于设置的版本, cmake 将停止处理并报错
cmake_minimum_required(VERSION 3.25)
project(hello_cmake CXX)
set(CMAKE_BUILD_TYPE DEBUG)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# 设置模块搜索目录
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
aux_source_directory(. MAIN_SRCS)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
add_executable(${PROJECT_NAME} ${MAIN_SRCS})
# 如果有 Policy CMP0074 is not set: find_package uses <PackageName>_ROOT variables. 警告
# 则参考: https://blog.csdn.net/yzlh2009/article/details/116428378 解决, 本文直接提升 cmake_minimum_required 为当前版本
set(calc_root $ENV{calc_root})
# 查找 calc 库
find_package(CALC MODULE REQUIRED)
if(CALC_FOUND)
include_directories(${calc_include_dir})
target_link_libraries(${PROJECT_NAME} ${calc_library})
endif()
# 复制库文件,
# 只有 windows 下需要, 当然如果把 calc.dll 复制到系统目录倒也不用复制
if(${CMAKE_HOST_WIN32})
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${calc_lib_dir}/${lib_calc_full_name} ${PROJECT_SOURCE_DIR}/bin/${lib_calc_full_name})
endif()
cmake/FindCALC.cmake
注意: FindCALC.cmake 规则为 FindPackageName.cmake , 其中 PackageName 为全大写
# calc 根目录
set(calc_root_dir ${calc_root})
set(calc_include_dir ${calc_root_dir}/include)
set(calc_lib_dir ${calc_root_dir}/lib)
message(STATUS "info - calc_root_dir : ${calc_root_dir}")
message(STATUS "info - calc_include_dir : ${calc_include_dir}")
message(STATUS "info - calc_lib_dir : ${calc_lib_dir}")
# 指定链接库目录
link_directories(${calc_lib_dir})
# 库名称
set(lib_calc_name calc)
# 库文件完整名称 windows 为 libcalc.dll , linux 为 libcalc.so
set(lib_calc_full_name ${CMAKE_SHARED_LIBRARY_PREFIX}calc${CMAKE_SHARED_LIBRARY_SUFFIX})
message(STATUS "info - lib_calc_name : ${lib_calc_name}")
message(STATUS "info - lib_calc_full_name : ${lib_calc_full_name}")
# 查找头文件
find_path(calc_include_dir calc.h PATHS "${calc_include_dir}")
# 查找库文件
find_library(calc_library calc PATHS "${calc_lib_dir}")
message(STATUS "info - calc_include_dir : ${calc_include_dir}")
message(STATUS "info - calc_library : ${calc_library}")
# 如果找到
if(calc_include_dir AND calc_library)
set(CALC_FOUND TRUE)
message(STATUS "Found calc: ${calc_library}")
endif()
# 如果没有找到, 并且 calc 为必须依赖项
if(NOT CALC_FOUND AND CALC_FIND_REQUIRED)
message(FATAL_ERROR "Coluld not find calc")
endif()
验证
linux 大同小异, 不再展示
F:\2023\code\cmake\hello_cmake>cmake -S . -G "Unix Makefiles" -B build && cmake --build build
-- The CXX compiler identification is GNU 10.3.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/program/tdmgcc/bin/g++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- info - calc_root_dir : F:/2023/code/cmake/calc
-- info - calc_include_dir : F:/2023/code/cmake/calc/include
-- info - calc_lib_dir : F:/2023/code/cmake/calc/lib
-- info - lib_calc_name : calc
-- info - lib_calc_full_name : libcalc.dll
-- info - calc_include_dir : F:/2023/code/cmake/calc/include
-- info - calc_library : F:/2023/code/cmake/calc/lib/libcalc.dll.a
-- Found calc: F:/2023/code/cmake/calc/lib/libcalc.dll.a
-- Configuring done
-- Generating done
-- Build files have been written to: F:/2023/code/cmake/hello_cmake/build
[ 50%] Building CXX object CMakeFiles/hello_cmake.dir/main.cpp.obj
[100%] Linking CXX executable F:/2023/code/cmake/hello_cmake/bin/hello_cmake.exe
[100%] Built target hello_cmake
F:\2023\code\cmake\hello_cmake>dir bin
驱动器 F 中的卷是 dox
卷的序列号是 34D2-6BE8
F:\2023\code\cmake\hello_cmake\bin 的目录
2023/01/25 05:49 <DIR> .
2023/01/25 05:49 <DIR> ..
2023/01/25 05:49 2,929,130 hello_cmake.exe
2023/01/25 05:49 99,384 libcalc.dll
2 个文件 3,028,514 字节
2 个目录 91,582,947,328 可用字节
F:\2023\code\cmake\hello_cmake>.\bin\hello_cmake.exe
1 + 2 = 3
hello world
F:\2023\code\cmake\hello_cmake>
上述操作有什么问题
- calc 库的头文件应当合并成1个, 这样引入的时候不用写那么多的 include
- 复制库文件部分应当写成一个函数, 这样调用方直接调用这个函数就好了
- 只验证了 tdm-gcc(windows) 和 g++(linux), 未验证 msvc
- 没有区分 debug 和 release
修正 find_package 脚本
- 修正自定义库头文件布局
- 添加两个库, 一个为必须依赖, 一个为可选依赖
- 添加复制库文件的函数
- 验证 msvc (windows) , tdm-gcc (windows) , g++ (linux)
第一个自定义库
此为必选依赖
第二个自定义库
此为可选依赖
主程序
tdm-gcc (windows) 验证
msvc (windows) 验证
g++ (linux) 验证
使用 wxWidgets 写一个 Hello World
首要目标是在 linux 和 windows 上运行起来
代码
https://docs.wxwidgets.org/3.2/overview_helloworld.html
// wxWidgets "Hello World" Program
// For compilers that support precompilation, includes "wx/wx.h".
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
class MyApp : public wxApp
{
public:
virtual bool OnInit();
};
class MyFrame : public wxFrame
{
public:
MyFrame();
private:
void OnHello(wxCommandEvent& event);
void OnExit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
};
enum
{
ID_Hello = 1
};
wxIMPLEMENT_APP(MyApp);
bool MyApp::OnInit()
{
MyFrame *frame = new MyFrame();
frame->Show(true);
return true;
}
MyFrame::MyFrame()
: wxFrame(NULL, wxID_ANY, "Hello World")
{
wxMenu *menuFile = new wxMenu;
menuFile->Append(ID_Hello, "&Hello...\tCtrl-H",
"Help string shown in status bar for this menu item");
menuFile->AppendSeparator();
menuFile->Append(wxID_EXIT);
wxMenu *menuHelp = new wxMenu;
menuHelp->Append(wxID_ABOUT);
wxMenuBar *menuBar = new wxMenuBar;
menuBar->Append(menuFile, "&File");
menuBar->Append(menuHelp, "&Help");
SetMenuBar( menuBar );
CreateStatusBar();
SetStatusText("Welcome to wxWidgets!");
Bind(wxEVT_MENU, &MyFrame::OnHello, this, ID_Hello);
Bind(wxEVT_MENU, &MyFrame::OnAbout, this, wxID_ABOUT);
Bind(wxEVT_MENU, &MyFrame::OnExit, this, wxID_EXIT);
}
void MyFrame::OnExit(wxCommandEvent& event)
{
Close(true);
}
void MyFrame::OnAbout(wxCommandEvent& event)
{
wxMessageBox("This is a wxWidgets Hello World example",
"About Hello World", wxOK | wxICON_INFORMATION);
}
void MyFrame::OnHello(wxCommandEvent& event)
{
wxLogMessage("Hello world from wxWidgets!");
}
linux 版
安装
sudo apt-get install pkg-config
sudo apt install libgtk-3-dev
然后直接安装即可
./configure && make && sudo make install
hello world
编译
ubuntu@ubuntu-cpp:~/code/cmake/wx_test$ ll
total 164
drwxrwxr-x 2 ubuntu ubuntu 4096 Jan 25 02:33 ./
drwxrwxr-x 3 ubuntu ubuntu 4096 Jan 25 02:27 ../
-rwxrwxr-x 1 ubuntu ubuntu 155328 Jan 25 02:33 hello*
-rw-rw-r-- 1 ubuntu ubuntu 1707 Jan 25 02:27 main.cpp
ubuntu@ubuntu-cpp:~/code/cmake/wx_test$
运行起来的效果
windows 版
在 Windows 上的环境搭建也很简单, 参考:
vs2019配置wxwidgets3.1.6教程
VS2019配置wxWidgets v3.1.6开发环境(超详细)
【配置】VS2015下wxWidgets 3.1.1开发环境
上述几篇博客已经写的很好, 不再赘述
cm 工具应当更新什么内容
需要添加
- 添加 clean 子命令
- 添加 --add-module 子命令
- 修正帮助文档的输出
待实现
- 全局配置和当前项目配置. 思路: 全局配置放在安装目录的 config 文件, 当前项目配置放在 .cm/config
- 命令别名. 思路: 命令别名放在 .cm/config
- 语言标准检测 思路: 提前准备几个特定的程序, 针对不同的标准进行验证
- 与第三方库整合
- doxygen 命令
- test 命令