本来是打算写一篇年终总结,随便和以往一样提一提自己的开源项目(长不大的plain framework)的一些进度,不过最近这一年对于这个项目实在是维护不多,实在难以用它作为醒目的标题。而最近由于使用了VS2022,微软居然自动识别了项目中的cmake(看来我是很久没有使用这个工具了),于是在想方设法将这个项目做到可以在windows平台上尽快提供编译支持,其中遇到了许多有关的技术问题,我觉得可以在这里为大家提供一定的借鉴,特别是自己想要拥有快速编写项目的技巧。分享虽然微不足道,但是也希望大家在此能够有所收获。

  2022的新春就要到了,新的一年(手动狗头,这是指旧历),祝福大家能够平安喜乐!

1、项目地址

  https://github.com/viticm/plain

  每次将地址放出来,感觉像是为自己的孩子做宣传,真的是可怜天下父母心。虽然这个孩子看起来实在太平庸了,可是我想说的是它还是有一定潜力的,至少在大多数的网络应用中都能够很好地发挥其作用。核心的框架并没有过多依赖,只需要依赖于标准的C/C++库即可,目前支持的语法为C++11。

  核心的模块:基础(basic)、网络(net)、文件(file)、系统(system)、数据库(database)、脚本(script)

  具体的我不再这里描述了,我之前对这个项目写过一些较为详细的介绍(估计也不够详细大家将就看吧)。

2、windows下的cmake

  接下来开始上主菜,一切都源于这张图:

  如果没有更改VS中默认的设置,那么它在打开文件夹时会自动识别目录下的CMakelist.txt,然后你就会发现这个页面了。它的目的是为提醒我们进行cmake相关的设置,有点像是游戏里面的引导功能,在IDE里微软的VS还是很注重用户体验的。虽然它出现了这个页面,但在跨平台开发的时候我仍然习惯于直接到相应的系统下直接开发,者或许是因为还没有真正体验到一个IDE跨平台开发的乐趣吧。但为了更好的开发编译,最近半个月时间几乎对于项目的维护都在了CMake这里,可以看到提交最多的注释为Update cmake。

  plain下面的CMakelist(根目录cmake/CMakelist.txt)

# Copyright 2017 Viticm. All rights reserved.
#
# Licensed under the MIT License(the "License");
# you may not use this file except in compliance with the License.
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
cmake_minimum_required(VERSION 2.8.12) set(PROJECT_NAME PlainFramework)
set(PF_VERSION 1.1.0)
set(PROJECT_DESC "Plain framework, based on c++ for net applictions") if (CMAKE_VERSION VERSION_LESS 3.0)
project(PlainFramework CXX C)
else()
cmake_policy(SET CMP0048 NEW)
cmake_policy(SET CMP0037 NEW)
project(PlainFramework VERSION ${PF_VERSION} LANGUAGES CXX C)
endif() # Call fplutil to get locations of dependencies and set common build settings.
include("inc/find_fplutil.cmake")
include("inc/common.cmake")
include("inc/internal_utils.cmake") if (NOT dependencies_gtest_dir)
set(dependencies_gtest_dir ${root_dir}/dependencies/googletest/googletest)
endif() if (NOT has_output_path) # This is the directory into which the executables are built.
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${root_dir}/plain/bin) # This is the directory into which the librarys are built.
set(LIBRARY_OUTPUT_PATH ${root_dir}/plain/lib) set(has_output_path 1) endif() #For utf8 no boom.
if (MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -wd4819")
endif() # Options that control the build configuration.
# To configure PlainFramework flags per build target, see the
# plainframework_configure_flags() function.
option(plainframework_build_tests "Build PlainFramework unit tests." ON) # Build plain framework plugins.
option(plainframework_build_plugins "Build PlainFramework plugins" ON) file(GLOB_RECURSE PLAINFRAMEWORK_HEADERS ${CMAKE_CURRENT_LIST_DIR}/framework/core/include *.h) set(VERSION_RC ${root_dir}/cmake/inc/version.rc.in) add_subdir(${plainframework_dir}/cmake plainframework plainframework) # Plugins.
if (plainframework_build_plugins)
add_subdir(${root_dir}/plain/plugins/cmake plugins plainframework)
endif() if(plainframework_build_tests)
add_subdir(${root_dir}/framework/unit_tests/cmake
${root_dir}/framework/unit_tests/cmake/build
plainframework)
if (NOT plainframework_no_app)
add_subdir(${root_dir}/plain/app/cmake
${root_dir}/plain/app/cmake/build
plainframework)
endif()
endif()

  root_dir(根目录)

  这个变量是当前项目的绝对路径,在PF项目中这个绝对路径是相对于CMakelist而言,也就是在子项目所在的根目录,这样是为了每个项目设置可以独立进行设置。

  这个变量在inc/common.cmake中,每个项目都这样设置:

set(root_dir ${CMAKE_CURRENT_LIST_DIR}/../.. CACHE INTERNAL "plainframework root directory")

  设置的路径为inc目录的上两级目录,PF项目中的cmake结构如下:

  如图inc的上两级目录就是plain,这样就获取到了项目所在的根目录,但这样的设置因人而异,或许大家能够想到更好的方式。

  让VS编译的时候不提示编码的警告(由于项目大胆的使用了google,因此整体的警告等级为最高4,而且所有警告都视为错误)

  作为纯粹的开发者,no boom的utf8文件才是可选的,由于历史原因微软各种自己使用的utf8文件都是加上了boom标记。

#For utf8 no boom.
if (MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -wd4819")
endif()

  has_output_path(是否指定输出目录)

  这个变量的目的为控制每个项目的输出路径,在VS中有生成后事件,也可以将生成的文件拷贝到自己想要的目录,但我自认为不太方便,直接就编译到指定目录才是王道。

  设置运行文件生成目录
  # This is the directory into which the executables are built.
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${root_dir}/plain/bin)

  在windows下这个目录输出工程的exe和dll等文件,在linux下输出的是可执行文件和so动态库。

  设置库文件生成目录
  # This is the directory into which the librarys are built.
set(LIBRARY_OUTPUT_PATH ${root_dir}/plain/lib)

  在windows下这个目录输出工程的lib和exp等文件,在linux下输出的是.a文件。

  add_dir(添加目录)

  在PF中为了保证每个子目录或者项目的根目录被正确设置,因此自己封装了这个添加目录的函数用以替换直接使用add_subdirectory。

# Safe add_subdirectory.
function(add_subdir target target_build project)
set_compiler_flags_for_external_libraries()
set(saved_root_dir${project} ${root_dir} CACHE INTERNAL "root dir cache")
add_subdirectory(${target} ${target_build})
set(root_dir ${saved_root_dir${project}} CACHE INTERNAL "root dir recover")
restore_compiler_flags()
endfunction(add_subdir)

  其目的保证当前的root_dir在子目录添加后不被更改,保证当前的编译变量在添加之后和之前一样(这里或许有些问题),个人认为这样暂时足够使用而且还挺方便的。

  下面的命令即是添加框架的所在目录:

add_subdir(${plainframework_dir}/cmake plainframework plainframework)

  在windows上使用cmake进行编译(是一个动图)

  运行测试(这个测试是自从编写db模块时才加入的,因此不会太多,在后续大版本中会坚持每一个接口增加):

  关于测试遇到的问题

  我这里要说的这个问题是windows上的,以前没有写测试用例的时候根本没有关注这个问题,其罪魁元首我先直接贴在最前面(internal_utils.cmake):

      if (NOT BUILD_SHARED_LIBS AND NOT pf_force_shared_crt)
# When Plain Framework is built as a shared library, it should also use
# shared runtime libraries. Otherwise, it may end up with multiple
# copies of runtime library data in different modules, resulting in
# hard-to-find crashes. When it is built as a static library, it is
# preferable to use CRT as static libraries, as we don't have to rely
# on CRT DLLs being available. CMake always defaults to using shared
# CRT libraries, so we override that default here.
string(REPLACE "/MD" "-MT" ${flag_var} "${${flag_var}}")
endif()

  这段代码是谷歌的,我之前一直连接的时候都是使用谷歌的静态库,其实都是为了方便。作为第三方的gtest,我直接将它作为自己的子模块,而且不能修改的子模块,用静态库我就不用在生成的时候去特意拷贝到自己的运行目录了(windows)。可是最后发现,运行测试的时候直接产生了一个异常断点,提示的是acrt_first_block==header。说实话对windows开发还缺少经验的我来说,遇到这个问题第一时间只能搜索查找资料,但是你会发现与此相关的都是内存泄漏。但转念我想到过,对于内存问题,PF是经过一段优化的,因此还是心存怀疑,于是使用vs进行调试这次提示的是内存访问冲突。

  最后让我怀疑是动态库的原因,是看到了一篇文章,这是无意发现的,这也许是经过了几天摸不着头脑,老天可怜的缘故吧。于是我仔细检查了所有的cmake编译脚本文件,很快就定位到了上述怀疑的地方。想不到当初为了偷懒,到头来却为自己带来了几天的麻烦,关于windows的内存分配可以搜索HeapAlloc关键字,里面有详细关于dll的内存分配。为了节省时间,加上本身不愿意再去做修改,因此加上了下面的编译脚本(当初只是为了不做这一步)。

# Copy gtest libraries.
if (MSVC AND pf_build_shared AND BUILD_SHARED_LIBS)
if (${CMAKE_BUILD_TYPE} STREQUAL "Debug")
add_custom_command(TARGET core_tests
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_BINARY_DIR}/bin/gtestd.dll ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
)
else()
add_custom_command(TARGET core_tests
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_BINARY_DIR}/bin/gtest.dll ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
)
endif()
endif()

  上面的目的很简单,在不同的类型下拷贝不同的gtest动态库。

  默认示例

  如果你使用PF进行开发,那么可以先从这个简单的示例开始(这里有点跑题,不过目前在cmake中遇到的问题已经差不多讲完了,那么就说说相关的题外话)。

  配置的细节就不用说了,新建一个cpp文件就可以快速开始使用PF了,如下面动图的开始那样(是不是很简单?)。

3、1.1.0

  在我编写这篇有关发布文章的时候,其实自己也在准备PF第一个版本的发布,以前没有正经的做过发布,这次发布出来是为了能够同大家一起研究和学习,不足之处还请指正。开源项目位于github,不过这个网站这两年很不稳定,还希望大家多一点耐心等待,要么就是用一下科学的工具吧。

  plain项目(提供了框架库和简单的示例)

  plain-simple(框架稍微详细的示例,里面包含了一个目前上线应用的例子)

  写在最后

  在这里再次祝福大家新年快乐,希望所有困扰我们的通通都消散,希望全世界和平美好!

  如果有需要可以加入我们的QQ群(348477824),这是一个潜水专用群,群主基本上已经是潜水几年了,但是如果你需要进行技术交流,那么可以到群里来闲聊。

最新文章

  1. ubuntu安装gitlab
  2. flume+hadoop
  3. C++ Primer : 第十一章 : 关联容器示例: 一个单词转换的map
  4. 记录asp.net网站停止运行原因的代码
  5. EF4.1之复杂类型
  6. POJ 1113 Wall 求凸包的两种方法
  7. usbmanger android 底下USB的工作模式
  8. Hololens 开发环境配置
  9. python3.4下django集成使用xadmin后台
  10. 大道至简第一章观后感——java伪代码
  11. geoserver发布地图服务WMS
  12. springboot集成quartz定时任务课动态执行
  13. busybox(一)浅析
  14. Bootstrap3基础 table-bordered/hover 表格加外边框和鼠标悬停对应行的背景色加深
  15. 一个数组中两个数的和为N,找出这两个数字的下标
  16. Xml文件删除节点总是留有空标签
  17. django-simple-captcha 验证码插件
  18. 【shell】各种括号()、(())、[]、[[]]、{}的使用
  19. Python 常用 PEP8 编码规范和建议
  20. HDU 1165 公式推导题

热门文章

  1. 如何在java web工程下建立存储property文件的文件夹,让Java程序直接读取
  2. 【手把手教程】uniapp + vue 从0搭建仿斗鱼虎牙直播App:腾讯云MLVB移动直播实践连麦PK+带货
  3. SpringBoot中Post请求提交富文本数据量过大参数无法获取的问题
  4. [Flink-源码分析]Blink SQL 回撤解密
  5. lldb调试C++总结(1)
  6. Windows串口之解决包含setupapi.h还提示找不到符号报错
  7. 【LeetCode】240. Search a 2D Matrix II 解题报告(Python & C++)
  8. 【LeetCode】558. Quad Tree Intersection 解题报告(Python)
  9. 【LeetCode】337. House Robber III 解题报告(Python)
  10. 【LeetCode】852. Peak Index in a Mountain Array 解题报告(Python)