本文主要实现的是在windows10下使用VSCode编辑器以及cmake工具来构建一个包含第三方库文件(此处为SFML)的项目的配置和调试。(因为SFML库文件的cmake比较难搞,,所以我自认为重点是其cmakelists.txt的编写)。
首先要保证VSCode可以正常使用MinGW编译器来编译运行C++程序、已经安装并能使用cmake。
build
一般按照项目的习惯是作为整个项目编译后的文件所在的文件夹,可以理解为变异的得到的可执行程序以及需要的资源的文件夹(即main.exe)CMakeFiles
这个是cmake执行时自动生成的一些文件,不用管external
这个一般就是我们项目引入第三方库文件的所在的文件夹,这里的文件一般要去你所需的库文件的官网下载 适合自己平台 的编译好的文件。(这里后面再说)include
这个一般是包含在编写代码时为了自动补全等需要的头文件等等内容。res
一般是一些项目的资源文件,如图片、视频、音频、纹理、模型等等。src
即我们项目自己编写的源码文件夹。CMakeLists.txt
这个文件是项目的一个配置文件,对于不同平台环境的使用者,都可以使用 cmake
命令来解释此文件来生成适合自己环境的项目编译等的 Makefile
文件。比如,我们win下完成的项目,只要编写一个合适的 CMakeLists.txt
,使用 cmake
命令就可以生成 win下的一个编译项目的方式(包括 Makefile
和资源文件、依赖文件等等的内容,一般就在 build
文件夹中) 。而另一个 unix 用户,也可以通过其 cmake 命令来生成自己平台下的 build
文件夹。这样无论是什么平台下的用户,都可以使用本平台的 make
命令来编译运行我们的项目。这也是使用 cmake
和 make
命令来管理项目的一个原因吧。test
文件夹等内容。external
文件夹、SFML以及cmake命令:对于 SFML
来说,需要去 SFML Downloads 下载适合本平台的版本,(比如我,设备安装的是MinGW64,所以我下载的就是GCC 7.3.0 MinGW (SEH) - 64-bit这个版本的)然后将其解压并复制到 external
文件夹下就行了,
其实就是相当于引入第三方库的 头文件 以及 需要链接的.a 文件,至于一些 .dll 文件,我们可以直接复制到编译好的程序的同级目录下即可,
对于前面两个引入,我们可以通过 g++ main.cpp -IIncludePath -LLibsPath -o main.exe
来搞定,当然为了简化输入命令的过程,可以通过编写 Makefile
文件来简化,,这样通过 make
命令就可以编译、运行、清理环境等等。
对于最后一个引入,我们可以通过编写 cmake 的 CMakeLists.txt
来实现将确定位置的 .dll
文件拷贝的操作。
整理一下这个流程:
main.cpp
等源文件和第三方文件的编译、链接操作,可以通过 make
命令对 Makefile
文件解释来实现;cmake
来解释 CMakeLists.txt
文件来生成适合本平台下的 Makefile
文件。(对于java系,引入第三方包,直接将jar包拖到IDE就能配置好,,当然C++下的IDE也可以实现这样的操作,,仅仅是IDE实现了 CMakeLists.txt
的一些功能,将其集成到一个按钮上)
接下来进入到具体到 使用SFML库 的 CMakeLists.txt
的编写。
CMakeLists.txt
的编写首先贴一下我当前 SFML
在项目中的位置:(上文提到的下载位置、解压、将
然后在项目的根目录中添加一个 项目名Config.h.in
文件,其中的内容如下(否则可能后续cmake会报错):
#define 项目名_VERSION_MAJOR @项目名_VERSION_MAJOR@
#define 项目名_VERSION_MINOR @项目名_VERSION_MINOR@
接着,在根目录中添加 CMakeLists.txt
文件,文件的内容如下(参考):
# cmake最低版本号要求
cmake_minimum_required (VERSION 3.0)
# 设置项目名
set(PROJECT_NAME sfml_learning_project)
project (${PROJECT_NAME})
set (${PROJECT_NAME}_VERSION_MAJOR 1)
set (${PROJECT_NAME}_VERSION_MINOR 0)
# 设置编译器参数,可以自己更改
set (CMAKE_CXX_STAND 11)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
# 配置一个头文件来传递一个cmake设置到源代码
configure_file (
"${PROJECT_SOURCE_DIR}/${PROJECT_NAME}Config.h.in"
"${PROJECT_SOURCE_DIR}/${PROJECT_NAME}Config.h"
)
# 设置引入的外部第三方库的路径
set (EXTERNAL_DIR ${PROJECT_SOURCE_DIR}/external)
# set(CMAKE_MODULE_PATH ${EXTERNAL_DIR})
# sfml
# SFML库的路径,要精确到官方下载的文件/lib/cmake/SFML
set (SFML_DIR ${EXTERNAL_DIR}/SFML-2.5.1/lib/cmake/SFML)
# set(SFML_STATIC_LIBRARIES TRUE)
# 输出路径,检查是否正确
message(${SFML_DIR})
# 调用需要的模块,此项命令依赖于上面那个路径的设置,对于SFML,项目用到啥 调用啥
find_package(SFML 2.5 COMPONENTS system window graphics network audio REQUIRED)
# 查找当前目录下的所有源文件并存入DIR_SRCS变量
aux_source_directory(src SRC_DIR)
# 递归列出所有源文件
file (GLOB_RECURSE SOURCE_FILES main.cpp)
# 添加一个可编译的目标到工程
add_executable (${PROJECT_NAME} ${SOURCE_FILES})
# 设置工作目录
set_property(TARGET ${PROJECT_NAME} PROPERTY VS_DEBUGGER_WORKING_DIRECTORY
${CMAKE_SOURCE_DIR}/res
)
# 添加链接库,项目需要啥,调用啥
target_link_libraries (${PROJECT_NAME} sfml-window sfml-graphics sfml-audio)
# target_compile_definitions(${PROJECT_NAME} PRIVATE SFML_INCLUDE_NONE)
# 将SFML/bin下的所有*.dll复制到 /build文件下,保证编译程序正常运行,不报缺少dll错误
file(GLOB_RECURSE PROJECT_DLL ${EXTERNAL_DIR}/*.dll)
message(${PROJECT_DLL})
# 复制库到工作目录
# POST_BUILD 在编译后操作
# copy命令拷贝单个文件,下面的 copy_directory是拷贝目录
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${PROJECT_DLL}
$
)
# 复制资源文件到工作目录
# 当项目中有用到素材时需要
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/res
$/res
)
# 针对苹果系统,未测试
if(APPLE)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND install_name_tool -change /usr/local/lib/libirrklang.dylib @executable_path/libirrklang.dylib ${PROJECT_NAME}
)
endif()
对于SFML,重要的是路径的配置(即 .hpp等头文件以及 .a链接文件):
# sfml
# SFML库的路径,要精确到官方下载的文件/lib/cmake/SFML
set (SFML_DIR ${EXTERNAL_DIR}/SFML-2.5.1/lib/cmake/SFML)
# set(SFML_STATIC_LIBRARIES TRUE)
# 输出路径,检查是否正确
message(${SFML_DIR})
# 调用需要的模块,此项命令依赖于上面那个路径的设置,对于SFML,项目用到啥 调用啥
find_package(SFML 2.5 COMPONENTS system window graphics network audio REQUIRED)
以及对 .dll 文件的拷贝:
# 将SFML/bin下的所有*.dll复制到 /build文件下,保证编译程序正常运行,不报缺少dll错误
file(GLOB_RECURSE PROJECT_DLL ${EXTERNAL_DIR}/*.dll)
message(${PROJECT_DLL})
# 复制库到工作目录
# POST_BUILD 在编译后操作
# copy命令拷贝单个文件,下面的 copy_directory是拷贝目录
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${PROJECT_DLL}
$
)
当编辑完毕 CMakeLists.txt
后,打开 cmake-gui
,选择项目的路径,以及编译后的路径,点击 Configure
没有错误后点击 Generate
即可在 build
文件夹生成适合本平台的整个项目:
此时,,我们可以在 build
文件夹中看到生成的文件(主要是 Makefile
)
到这一步就相当于是我们在IDE中配置好了整个项目的环境,如项目的名称、路径、引入的第三方库文件的路径等等内容,所以 只要build不删,我们只需执行一次cmake命令
之后我们就可以在 src
中编写项目的代码,测试时就到 build
文件夹下,(因为我们已经通过 cmake
生成了项目的 Makefile
文件,所以直接 make就行了),执行 mingw32-make.exe -j8 V=1
即可完成编译(MinGW把自带的make更名了,其中 -j8
表示并行调用8和核心编译, V=1
表示显示中间信息):
在 build
文件夹下可以看到编译后的程序所需的文件:
其中有源码编译后的程序、有所需的资源文件夹、有所需的 .dll 文件等等。
这里使用的源程序为:
#include
#include
#include
using namespace std;
sf::RenderWindow window(sf::VideoMode(1920,1080), "Tree");
void start(float inix, float iniy, float degree, float length)
{
if (length < 1.0f) return;
else
{
float newlength=0.67f * length;
float finx = inix + (newlength * (float)cos(degree * (3.14 / 180.0f)));
float finy = iniy + (newlength * (float)sin(degree * (3.14 / 180.0f)));
sf::Vertex line[]= {
sf::Vertex(sf::Vector2f(inix, iniy)),
sf::Vertex(sf::Vector2f(finx, finy))
};
start(finx, finy, degree+60.0f, newlength);
start(finx, finy, degree-30.0f, newlength);
window.draw(line, 2, sf::Lines);
//line.setFillColor(sf::Color::Blue);
//window.display(); // Uncomment for animation
}
}
int main()
{
window.clear();
start(1000, 799, -90, 350);
window.display();
sf::Event event;
while (window.isOpen())
{
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed) window.close();
}
}
return 0;
}
进入 build
文件后运行即可:
后台会不断的输出 Failed to set DirectInput device axis mode: 1
这个可以貌似是官方的一个bug,,,不影响测试我就没管。
整个配置操作应该就结束了,如果有错误欢迎指出交流!(author: 31415926535x)