- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章详解如何使用VSCode和CMake构建跨平台的C/C++开发环境由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
日前在学习制作LearnOpenGL教程的实战项目Breakout游戏时,希望能将这个小游戏开发成跨平台的,支持在多个平台运行。工欲善其事必先利其器,首先需要做的自然是搭建一个舒服的跨平台C/C++开发环境,所以这篇文章主要就是记录环境搭建的整个过程,踩到的一些坑,以及对应的解决办法.
正文开始之前,先来阐述几个问题 。
为什么选择使用VSCode 。
为什么使用CMake 。
最终实现的开发流程是怎样的VSCode编写代码快捷键Ctrl+Shift+B,调用CMake完成本地项目生成(Mac快捷键Command+Shift+B)快捷键Ctrl+B,完成项目的编译构建与运行(Mac快捷键Command+B)快捷键F5,完成项目的调试与运行(VSCode的F5调试运行,为了能够实现调试功能额外做了许多工作,所以启动会有些慢,因此在不需要调试的时候,直接使用Ctrl+B编译运行看效果会更快些) 。
CMake与VSCodeCMake的获取,可以查看CMake官网 。
VSCode的获取,可以查看VSCode官网 。
关于CMake与VSCode如何安装,比较简单,网上也有很多教程,这里就不详细介绍了 。
VSCode插件推荐安装在VSCode的Extensions面板中搜索下面的插件名即可,记得看清作者名,不要下错啦插件 。
插件名 | 作者 | 描述 |
---|---|---|
C/C++ | Microsoft | 提供C/C++的代码提示,跳转,调试等诸多功能,官方出品,基本是C/C++开发必备了 |
CMake | twxs | 提供CMake语法的高亮显示以及代码段提示 |
这里给出例子工程的文件目录情况,并不完整,但具有一定的代表性,不仅涉及源代码的编译,同样包含了静态库,动态库的加载,以及资源文件的读取等问题 。
Breakout 。
├── 3rd // 第三方库 。
│ ├── glfw // 一个静态库目录 。
│ ├── irrKlang-1.6.0 // 一个动态库目录 。
│ └── FindIrrKlang.cmake // cmake文件 。
├── resources // 资源目录 。
│ ├── textures // 存放贴图文件 。
│ └── shaders // 存放shader文件 。
├── src // 源代码目录 。
│ ├── game // 源代码子目录 。
│ │ ├── game.h 。
│ │ └── game.cc 。
│ └── main.cc 。
└── CMakeLists.txt // cmake文件 。
本文仅着重介绍为了完成示例项目开发,解决特定问题而使用的一些cmake语句 。
cmake的所有语句都写在CMakeLists.txt中,cmake会根据该文件中的配置完成最终的编译,构建,打包,测试等一系列任务 。
一个简单的CMakeLists.txt如下所示,完整的文件可以查看这里 。
# cmake最低版本号要求 。
cmake_minimum_required (VERSION 2.8) 。
# 设置PROJECT_NAME变量 。
set(PROJECT_NAME Breakout) 。
# 设置工程名 。
project (${PROJECT_NAME}) 。
# 查找当前目录下的所有源文件并存入DIR_SRCS变量 。
aux_source_directory(src DIR_SRCS) 。
# 添加一个可编译的目标到工程 。
add_executable (${PROJECT_NAME} ${DIR_SRCS}) 。
如何编译一个文件夹下的所有源代码 。
在开发过程中,由于架构设计或是为了便于管理与查找,源文件一般会根据不同的功能存放在不同的文件夹中,文件夹中又可能嵌入文件夹,所以需要一条语句能够获取所有的源文件进行编译,而不用每新创建一个源文件,就修改一次编译指令 。
# 递归列出所有源文件 。
file (GLOB_RECURSE SOURCE_FILES *.cc) 。
# 添加一个可编译的目标到工程 。
add_executable (${PROJECT_NAME} ${SOURCE_FILES}) 。
上面这条file命令会递归列出所有.cc文件,并存入SOURCE_FILES变量,然后将SOURCE_FILES表示的所有.cc文件添加到目标即可,从而解决多源文件编译问题 。
为了不重复造轮子,开发中不可避免的要引入其他第三方库。正常情况下,这个第三方库也会是一个CMake工程(或是库的开发者直接提供已经编译好的库) 。
以示例项目引入的glfw库为例 。
1.添加submodule引入glfw(glfw正好是github上的一个开源项目),或是直接将第三方库的源码放到自己的目录中 。
git submodule add https://github.com/glfw/glfw.git 。
2.使用add_subdirectory命令,将glfw所在的文件夹添加到编译的任务列表中 。
# 保证glfw dir被编译 。
add_subdirectory (${GLFW_DIR}) 。
3.将glfw的头文件目录添加到头文件搜索路径中 。
# 添加头文件搜索路径 。
include_directories (${GLFW_DIR}/include) 。
4.链接glfw库,target_link_libraries命令用来链接目标与库文件,第一个参数就是我们的构建目标,后面可以跟多个参数,来表示链接多个库 。
# 添加链接库 。
target_link_libraries (${PROJECT_NAME} glfw) 。
以示例项目引入的irrKlang库为例,它并不是一个开源项目,不过好在它提供了已经在多个平台上编译好的库,所以我们需要根据不同的平台来设置引入不同的库文件 。
1.利用find_package引入外部依赖包,它可以帮我们找到官方预定义的许多依赖包模块,当未在官方预定义的依赖中找到时,会再查找FindXXX.cmake文件,执行该文件从而找到XXX库.
# IrrKlang 。
find_package (IrrKlang REQUIRED) 。
2.先新建FindIrrKlang.cmake文件,由它来负责具体的irrKlang库加载。部分语句如下所示,主要是根据当前平台的不同,设置不同的头文件路径,库路径,库所在目录等变量。用到的find_library语句可以实现直接根据库的base name(即不需要lib,so等),找到对应的库,并存入IRRKLANG_LIBRARY变量 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
find_path(IRRKLANG_INCLUDE_DIR NAMES irrKlang.h PATHS
"${3RD_DIR}/irrKlang-1.6.0/include"
)
IF(WIN32) # win32平台
if
(
"${CMAKE_CXX_COMPILER_ID}"
STREQUAL
"MSVC"
)
message(STATUS
"Using MSVC"
)
set (IRRKLANG_LIB_DIR
"${3RD_DIR}/irrKlang-1.6.0/lib/Win32-visualStudio"
)
set (IRRKLANG_BIN_DIR
"${3RD_DIR}/irrKlang-1.6.0/bin/Win32-visualStudio"
)
find_library(IRRKLANG_LIBRARY NAMES irrKlang PATHS ${IRRKLANG_LIB_DIR})
elseif(
"${CMAKE_CXX_COMPILED_ID}"
STREQUAL
"GNU"
)
message(STATUS
"Using GCC"
)
set (IRRKLANG_LIB_DIR
"${3RD_DIR}/irrKlang-1.6.0/lib/Win32-gcc"
)
set (IRRKLANG_BIN_DIR
"${3RD_DIR}/irrKlang-1.6.0/bin/Win32-gcc"
)
find_library(IRRKLANG_LIBRARY NAMES libirrKlang.a PATHS ${IRRKLANG_LIB_DIR})
endif()
elseif(APPLE) # mac平台
set (IRRKLANG_BIN_DIR
"${3RD_DIR}/irrKlang-1.6.0/bin/macosx-gcc"
)
find_library(IRRKLANG_LIBRARY NAMES libirrklang.dylib PATHS
"${3RD_DIR}/irrKlang-1.6.0/bin/macosx-gcc"
)
elseif(UNIX AND NOT APPLE) # 等同于linux平台
set (IRRKLANG_BIN_DIR
"${3RD_DIR}/irrKlang-1.6.0/bin/inux-gcc"
)
find_library(IRRKLANG_LIBRARY NAMES IrrKlang PATHS
"${3RD_DIR}/irrKlang-1.6.0/bin/linux-gcc"
)
endif()
|
3.将找到的irrKlan头文件添加到头文件搜索路径中 。
include_directories (${IRRKLANG_INCLUDE_DIR}) 。
4.链接irrKlang库 。
# 添加链接库 。
target_link_libraries (${PROJECT_NAME} glfw ${IRRKLANG_LIBRARY}) 。
跨平台的代码,一般使用utf-8编码格式的代码,更加通用,也可以保证在MacOS或者Linux平台上的正常编译.
但是visual studio默认编译文件的编码是utf-8 with bom,在没有中文的情况下,直接编译是没有问题的,然而当源文件含有中文时(比如中文注释),则可能会出现异常,报一些莫名其妙的语法错误。解决办法是通过CMake语句通知MSVC编译时采用utf-8编码 。
# 设置MSVC编译编码 。
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/source-charset:utf-8>") 。
当编译构建生成可执行文件后,我们希望可以直接通过命令行命令启动可执行文件来查看效果。但是由于工作目录的问题,可能会导致出现资源文件找不到,或者库加载失败问题 。
对于visual studio工程,可以通过CMake语句设置其工作目录,但是这个工作目录仅在通过visual studio调试启动时才会生效,但对于直接启动可执行文件的情况仍然是没用的 。
# 设置工作目录 。
set_property(TARGET ${PROJECT_NAME} PROPERTY VS_DEBUGGER_WORKING_DIRECTORY 。
${CMAKE_SOURCE_DIR}/resources 。
) 。
所以只能将资源文件目录放置到可执行文件所在目录下,以保证一定能加载到需要的资源,这可以通过CMake的自定义命令实现 。
# 复制资源文件到工作目录 。
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD 。
COMMAND ${CMAKE_COMMAND} -E copy_directory 。
${CMAKE_SOURCE_DIR}/resources 。
$<TARGET_FILE_DIR:${PROJECT_NAME}>/resources 。
) 。
这条语句的功能是在编译结束后,将指定的资源目录复制到生成的可执行文件所在的目录.
同样的,对于一些动态库,比如dylib,dll等也需要复制,不过注意最好在编译前就将它们复制到目标目录,使用PRE_BUILD指明命令执行的时机 。
# 复制库到工作目录 。
add_custom_command(TARGET ${PROJECT_NAME} PRE_BUILD 。
COMMAND ${CMAKE_COMMAND} -E copy_directory 。
${IRRKLANG_BIN_DIR} 。
$<TARGET_FILE_DIR:${PROJECT_NAME}> 。
) 。
在Mac上启动可执行文件时,一直遇到一个动态库无法加载的报错 。
dyld: Library not loaded: /usr/local/lib/libirrklang.dylib 。
Referenced from: ... 。
Reason: image not found 。
这是由于在编译生成动态库时,可以指定动态库的加载路径,比如我们引入的libirrklang库默认会到/usr/local/lib目录下查找dylib文件 。
简单的解决方式,自然是通过install命令,将libirrklang.dylib文件安装到/usr/local/lib目录下,不过为了不“污染”其他目录,更希望可执行文件加载的是我们放置在其所在目录下的libirrklang.dylib文件。为了实现这个目标,我们添加下面的CMake语句 。
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() 。
判断如果是Mac平台,则通过add_custom_command调用install_name_tool命令,来修改应该应用程序对动态库的查找路径。其中的@executable_path就表示可执行文件所在目录 。
CMake的配置文件已经基本准备完毕了,接下来就是怎样结合VSCode更方便的调用CMake的问题了 。
Ctrl+Shift+B是VSCode调用task的默认快捷键,task定义在.vscode目录下的task.json文件中,一般使用task来完成编译等任务,VSCode任务系统提供了丰富的参数配置,我们可以利用它完成很多自定义任务 。
定义一个task,执行cmake ..命令,完成本地项目的编译生成。Linux会生成Makefile,MacOS生成Makefile或Xcode工程,Windows下生成Visual Studio工程。注意这里的..表示的是上层目录,因为我们会在项目根目录下新建一个build文件夹,然后在这个文件夹内完成一系列的编译工作,这样cmake生成的中间文件都在build目录,不会“污染”开发目录(将build目录加入.gitignorej即可忽略CMake所产生的所有中间文件),在编译出问题的时候也可以直接删除buidl目录重新编译 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
{
"label"
:
"cmake"
,
// task的名字
"type"
:
"shell"
,
"command"
:
"cmake"
,
"args"
: [
// "-DCMAKE_BUILD_TYPE=${input:CMAKE_BUILD_TYPE}",
".."
],
"options"
: {
"cwd"
:
"build"
// 表示当前执行目录build文件夹
},
"group"
:
"build"
,
"presentation"
: {
// 一些控制台显示配置
"echo"
:
true
,
"reveal"
:
"always"
,
"focus"
:
false
,
"panel"
:
"shared"
,
"showReuseMessage"
:
true
,
"clear"
:
true
},
// Use the standard MS compiler pattern to detect errors, warnings and infos
"problemMatcher"
:
"$msCompile"
,
"dependsOn"
:[
"mkbuild"
]
// 依赖的任务,在本任务执行前先执行mkbuild任务
}
|
在cmake ..命令执行前,先通过task执行mkdir新建build文件夹。其中通过windows参数,区分不同平台设置不同的参数 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
{
"label"
:
"mkbuild"
,
"type"
:
"shell"
,
"command"
:
"mkdir"
,
// 调用的命令
"args"
: [
// 命令参数
"-p"
,
"build"
],
"windows"
:{
// windows平台使用mkdir -Force build新建文件夹
"args"
: [
"-Force"
,
"build"
]
},
"group"
:
"build"
,
"presentation"
: {
"echo"
:
true
,
"reveal"
:
"always"
,
"focus"
:
false
,
"panel"
:
"shared"
,
"showReuseMessage"
:
true
,
"clear"
:
true
},
// Use the standard MS compiler pattern to detect errors, warnings and infos
"problemMatcher"
:
"$msCompile"
,
}
|
当按下Ctrl+Shift+B时,VSCode将弹出所有可执行的task,选择执行cmake task即可。由于定义了依赖(dependsOn),在cmak task执行前,将自动先执行mkbuild task 。
在启动可执行文件前,先通过cmake --build .构建生成可执行文件 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
{
"label"
:
"compile"
,
"type"
:
"shell"
,
"command"
:
"cmake --build ."
,
"options"
: {
"cwd"
:
"build"
},
"group"
:
"build"
,
"presentation"
: {
// Reveal the output only if unrecognized errors occur.
"reveal"
:
"always"
,
"clear"
:
true
},
// Use the standard MS compiler pattern to detect errors, warnings and infos
"problemMatcher"
:
"$msCompile"
}
|
在可执行文件生成后,通过task启动可执行文件。其中的${workspaceFolderBasename}是VSCode的内置变量,表示工程名。更多的内置变量介绍可以查看这里 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
{
"label"
:
"run"
,
"type"
:
"shell"
,
"command"
:
"./${workspaceFolderBasename}"
,
"group"
:
"build"
,
"presentation"
: {
"echo"
:
true
,
"reveal"
:
"always"
,
"focus"
:
false
,
"panel"
:
"shared"
,
"showReuseMessage"
:
true
,
"clear"
:
true
},
"options"
: {
"cwd"
:
"build"
},
"windows"
:{
"options"
: {
"cwd"
:
"build/Debug"
// windows visual studio项目会默认多生成Debug/Release目录
},
},
// Use the standard MS compiler pattern to detect errors, warnings and infos
"problemMatcher"
:
"$msCompile"
,
"dependsOn"
:[
"compile"
]
// 在run任务执行前先执行compile任务,确保修改的代码生效
}
|
通过Ctrl+B直接调用run任务。由于编译运行这个任务经常要用到,如果依然通过Ctrl+Shift+B弹出所有任务,再进一步选择就会有些麻烦,所以定义一个快捷键(读者可以用同样的方法设置自己喜欢的快捷键)来直接运行run任务打开VSCode快捷键设置 。
在弹出的界面中输入“run build task”搜索,并修改其快捷键 。
点击右上角的翻转按钮,进入快捷键文件配置 。
在打开的文件中,为刚配置的快捷键添加参数,告诉它直接启动名字叫“run”的task 。
1
2
3
4
5
|
{
"key"
:
"ctrl+b"
,
"command"
:
"workbench.action.tasks.runTask"
,
"args"
:
"run"
}
|
VSCode通过.vscode目录下的launch.json实现对多个平台多种语言的调试支持 。
通过F5完成项目的调试与运行配置launch.json文件以支持C/C++项目的调试 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version"
:
"0.2.0"
,
"configurations"
: [
{
"name"
:
"Launch Debug"
,
//名称
"type"
:
"cppdbg"
,
//调试类型,除使用msvc进行调试外,均为该类型
"request"
:
"launch"
,
"program"
:
"${workspaceFolder}/build/${workspaceFolderBasename}"
,
//指定C/C++程序位置
"args"
: [],
//指定运行参数
"stopAtEntry"
:
false
,
"cwd"
:
"${workspaceFolder}/build"
,
//指定工作目录
"preLaunchTask"
:
"compile"
,
//在调试前会先调用这个task编译构建程序
"environment"
: [],
"externalConsole"
:
false
,
"osx"
: {
//macOS的特定配置
// "miDebuggerPath": "/Applications/Xcode.app/Contents/Developer/usr/bin/lldb-mi", //修改使用的lldb-mi,一般不需要修改
"MIMode"
:
"lldb"
//指定使用lldb进行调试
},
"linux"
: {
//linux的特定配置
"MIMode"
:
"gdb"
,
//指定使用gdb调试
"setupCommands"
: [
{
"description"
:
"Enable pretty-printing for gdb"
,
"text"
:
"-enable-pretty-printing"
,
"ignoreFailures"
:
true
}
]
},
"windows"
: {
//windows的特定配置
"type"
:
"cppvsdbg"
,
//指定使用msvc进行调试
"program"
:
"${workspaceFolder}/build/Debug/${workspaceFolderBasename}.exe"
,
//指定C/C++程序位置
}
}
]
}
|
F5是VSCode调试运行的默认快捷键,不需要额外配置,启动调试后的界面如下所示 。
通过使用本地工具完成调试由于cmake在windows平台会默认生成Visual Stduio工程,所以也可以直接打开生成的解决方案,通过Visual Studio进行调试Mac平台可以使用cmake .. -GXcode命令指定生成XCode工程,然后通过XCode进行调试 。
以上就是详解如何使用VSCode和CMake构建跨平台的C/C++开发环境的详细内容,更多关于VSCode CMake构建跨平台 C/C++开发环境的资料请关注我其它相关文章! 。
原文链接:https://www.cnblogs.com/iwiniwin/p/13705456.html 。
最后此篇关于详解如何使用VSCode和CMake构建跨平台的C/C++开发环境的文章就讲到这里了,如果你想了解更多关于详解如何使用VSCode和CMake构建跨平台的C/C++开发环境的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在开发一组应用程序,它们协同工作以创建一个用于处理计量数据的系统。我想让它们松散耦合有几个原因,并且系统应该可以由第三方扩展,因此应用程序将通过消息传递绑定(bind)在一起。 我正在寻找一种消息
如果我使用 python 2.6 和 Qt 为 windows 创建一个 gui,然后想在 solaris 或 linux 世界中运行。 我在两个系统上都需要什么,我猜两个平台都需要 2.6 和 Qt
我正在运行 Linux Ubuntu 10.04,我有一台 Windows 7 机器和一台运行 Mac OS X 10.6.4 的 MacBook。我如何编写一个简单的 C 程序(如 不是 QT!),
前言 今天给大家分享一个.NET开源(MIT License)、免费、跨平台(适用于 Windows、MacOS 和 Linux )、使用简单的面部识别库:FaceRecognitionDotNet
我知道汇编语言通常不是跨平台的。即使使用像 NASM 这样的东西,对于不同的架构和平台,您仍然需要不同的代码,这些架构和平台具有不同的运行时和诸如中断之类的东西的实现。但是如果有人因为喜欢汇编语言而想
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 8年前关闭。 Improve thi
This question already has answers here: How to play audio? (20个答案) 12天前关闭。 我正在编写一个dhtml应用程序,该应用程序创建系
我正在使用MonoGame开发一款游戏,该游戏使用SoundEffectInstance来实现游戏中的音效。在可以创建的SoundEffect实例数量以及可以同时播放的最重要实例方面,不同平台受到什么
如何在 java 中找到并运行默认计算器而不使我的程序依赖于平台。我可以对每个主要操作系统的所有路径进行硬编码,然后找到该人正在使用的操作系统,然后使用该操作系统各自的路径。但是,我不想那样做,有没有
有没有办法使用捏合来放大共享的Xamarin Forms,我只找到了每个平台的实现。 最佳答案 您可以使用 Pan Gesture 来实现它。这里有一个很好的在 PanContainer 中包装图像的
是否有最好/好的方法来同时为 Android 和 iOS(以及 Mac OS X)开发跨平台应用程序,例如游戏? 只是简单地开发一个仅使用 OpenGL 和 C/C++ 的应用程序应该很简单,不是吗?
我想知道 CSS 行为是否会随着操作系统的不同而变化。我的 css 对于 vista 和 win xp proffesional 对于相同版本的浏览器来说有点不同。我在 vista + ie8 和 x
我需要一种跨平台的方式来检查给定的文件路径是否是绝对的而不使用Pathname 库。为此,我唯一希望依赖的库是 File。它需要跨平台和跨实现,因此无论是 Ruby MRI、JRuby、Rubiniu
我正在尝试寻找一种跨平台的方法来从文件末尾删除 X 字节。 目前我发现: 特定于平台的解决方案(例如 truncate for posix):这是我不想要的,因为我希望 C++ 程序可以在多个平台上运
我想将可执行文件从一个目录复制到另一个目录。 源目录包括各种我不关心的文件(构建工件)。我只想使用适用于 OS X 和 Linux 的 bash 脚本获取可执行文件。 可执行文件是指具有可执行权限的文
我需要能够在服务器端处理简单 HTTP GET/PUT 请求的库。有一些特殊要求: 应该是跨平台的(这是主要因素) 支持多线程。 高性能 支持 HTTPS 许可证应允许链接专有代码(LGPL、BSD)
我正在寻找一种可用于从 Windows 和 Mac OSX 计算机上传大型 (~2GB) 文件的技术。应该可以根据请求/错误暂停和恢复上传。具有基本计算机技能的用户应该可以轻松安装最终产品。 我正在考
我正在寻找一种使用 java 播放 .flv 文件的方法。这意味着我需要一个跨平台的 ffmpeg 库。我一直在玩弄 jmf 和 fobs4jmf,但我无法在 linux 中播放,因为我需要一个本地库
我想在基于浏览器的应用程序中做的一件事是允许用户选择一些文本(不是在 中,只是普通的文本!),然后让我的应用程序弹出一个然后可以与下一个交互的小工具栏(在我的例子中,添加注释)。 我在 google
对于 PyInstaller 中的新功能,我们需要一个命令行选项来接收其中包含任何分隔符的字符串。这是讨论:https://github.com/pyinstaller/pyinstaller/pul
我是一名优秀的程序员,十分优秀!