一.项目任务
1.完成一个CMake工程生成一个动态库,该动态库包含内容:
(1)包含一个StringUtil类,该类具有Split和Trim2个静态方法。上述2个接口的定义如下:
/// 删除字符串两侧的空格, s的值不会被修改
/// @param s const string& 源字符串
/// @return string
static string Trim(const string& s);
/// 把输入目标字符串按照分隔符(字符串)分割为一组字符串, 追加到vec
/// @param s const string& 源字符串
/// @param c const string& 分割字符串
/// @param vec StringList& 输出参数,分解后的字符串向量
/// @return void
static void Split(StringList& vec, const string& s, const string& c);
2.完成动态链接库中方法的测试
二.动态链接库的生成
1.首先构建如下项目目录
1.my_lib文件夹
2.在my_lib文件夹下新建bin文件夹、my_lib.cpp、my_lib_export.h、CMakeLists.txt
3.在my_lib的同级目录下新建另一个CMakeLists.txt
2.源码如下
(1)my_lib.cpp
(如果想要获得lib文件则必须使用__declspec(dllexport),需要在每一个类以及函数前加这个前缀,才能生成lib文件,同样在后面的动态链接库的使用时要用到__declspec(dlimport)前缀,这样才能调用封装在动态链接库中的函数。)
#include "my_lib_export.h"
#pragma once
#define MY_LIB_API __declspec(dllexport)
void MY_LIB_API StringUtil::Split(vector<string>& res,const string &str, const string &pattern)
{
if(str == "")
return;
//在字符串末尾也加入分隔符,方便截取最后一段
string strs = str + pattern;
size_t pos = strs.find(pattern);
while(pos != strs.npos)
{
string temp = strs.substr(0, pos);
res.push_back(temp);
//去掉已分割的字符串,在剩下的字符串中进行分割
strs = strs.substr(pos+pattern.size(), strs.size());
pos = strs.find(pattern);
}
}
void MY_LIB_API StringUtil::Trim(const string& s)
{
string s1=s;
if (s1.empty())
{
return ;
}
s1.erase(0,s1.find_first_not_of(" "));
s1.erase(s1.find_last_not_of(" ") + 1);
}
(2)my_lib_export.h
#pragma once
#define MY_LIB_API __declspec(dllexport)
#include <iostream>
#include<string>
#include<vector>
#include<stdio.h>
#include<sstream>
using namespace std;
class MY_LIB_API StringUtil{
public:
static void Trim(const string& s);
static void Split(vector<string>& vec, const string& s, const string& c);
};
(3)my_lib文件夹下的CMakeLists.txt
PROJECT(CC1)
ADD_LIBRARY(PRD_6 SHARED my_lib.cpp)
(4)my_lib同目录下的的CMakeLists.txt
#cmake的最低版本
cmake_minimum_required(VERSION 3.24.0)
#工程文件名称,可以与内部的CMakeLists.txt中项目名称不一致,最终会生成两个sln文件,项目CC2将会在demo目录下生成,内部CMakeLists.txt中所创建的CC1项目会添加到bin文件夹里
project(CC2)
#将构建添加到bin文件夹中
ADD_SUBDIRECTORY(my_lib bin)
3.使用cmd进入到my_lib文件夹,执行cmake指令:
cmake . .
4.my_lib文件夹中或bin文件夹中会生成CC2.sln或者CC1.sln。任选一个打开(二者效果相同)进行编译,编译后将会在bin/Debug中生成PRD_6.dll与PRD_6.lib,调用动态链接库时将会使用到这两个文件,二者就是所保存的封装的类与函数。
三.动态链接库的使用
1.构建项目目录
文件结构与上面基本一致,但需要将生成的PRD_6.dll与PRD_6.lib放到bin文件夹下
2.源码
1.main.cpp
#pragma comment(lib,"PRD_6.lib")
#调用lib动态链接库
#include "my_lib.h"
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main()
{
StringUtil S;
string s1="kbcxajcbaaanjknkaaad";
string s2="aaa";
vector<string> res;
S.Split(res,s1,s2);
cout << res[0]<<endl;
cout << res[1] << endl;
cout << res[2] << endl;
return 0;
}
2.my_lib.h
#pragma comment(lib,"PRD_6.lib")
#define MY_LIB_API __declspec(dllimport)
#头文件中需要添加调用的类,并在类名前加 __declspec(dllimport)前缀,如果原来的动态链接库只是写了函数,则在这里就在需要写出用到的函数并在函数名前加__declspec(dllimport)前缀
#include <iostream>
#include<string>
#include<vector>
#include<stdio.h>
#include<sstream>
using namespace std;
class MY_LIB_API StringUtil{
public:
static void Trim(const string& s);
static void Split(vector<string>& vec, const string& s, const string& c);
};
3.demo里的CMakeLists.txt
cmake_minimum_required(VERSION 3.10.0)
# 最低版本要求 cmake 构建工具小于3.10.0将报错
project(demo)
# 工程项目名称
#aux_source_directory(${CMAKE_SOURCE_DIR} RP_ALL_SRC)
# 这里对 ${CMAKE_SOURCE_DIR} 也就是当前CMakeList.txt 目录下的*.cpp输出到变量
# RP_ALL_SRC (ROOTPATH_ALL_SRC 意为顶层目录所有源码)
include_directories(test_lib) # 添加头文件包含目录
#link_directories(G:/VStudio/SHIXI_PRD6/mylib)
# 添加链接库文件目录 注意,此行必须在add_executable前,否则编译器在生成main.exe时将无法找到库文件
add_executable(main main.cpp)
target_link_libraries(main PRD_6.lib)
#为生成目标添加一个库 可以是多个 比如 target_link_libraries(main lib1 lib2)
4.与demo同目录下的CMakeLists.txt
cmake_minimum_required(VERSION 3.24.0)
project(CC)
ADD_SUBDIRECTORY(demo bin)
5.将上面所得到的PRD_6.lib以及PRD_6.dll复制并放到bin文件夹中
3.使用cmd进入到demo文件夹中,执行cmake指令
cmake . .
4.编译执行完成,将会在demo文件夹以及bin文件夹下生成CC.sln以及demo.sln(二者相同)任选一个打开进行编译
5.成功调用动态链接库的函数,输出结果
四.总结
这次实验中遇到了许多的问题,例如没有生成lib文件,不能成功调用lib文件等等,不过在不断的尝试与查找资料的努力下,最终还是成功的完成了任务,收获满满!