本来是打算写一篇年终总结,随便和以往一样提一提自己的开源项目(长不大的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),这是一个潜水专用群,群主基本上已经是潜水几年了,但是如果你需要进行技术交流,那么可以到群里来闲聊。

关于cmake和开源项目发布的那些事(PF)的更多相关文章

  1. 如何把开源项目发布到Jcenter

    转载自:https://www.jianshu.com/p/f66972f0607a 首先我们应该注册一个JFrog Bintray的账号 Jfrog Bintray官网 这里我们可以注意到那个绿色的 ...

  2. YourSQLDba开源项目发布到codeplex网站了

    今天登录YourSQLDba的官方网站http://yoursqldba.grics.ca/index_en.shtml,发现YourSQLDba项目已经发布到开源网站http://www.codep ...

  3. AndroidStudio怎么将开源项目发布到jcenter

    前言 自己在网上搜了一大堆,大体就两种方法,而我选择的是其中代码少的的方法,不过他们或多或少留下了少许的坑,(按他们的方法我是上传成功,但不能发布到jCenter上去,也可能是我自己的问题o(≧v≦) ...

  4. [转]使用Gradle发布Android开源项目到JCenter

      转自:http://blog.csdn.net/maosidiaoxian/article/details/43148643 使用Gradle发布Android开源项目到JCenter 分类: G ...

  5. 使用Gradle发布Android开源项目到JCenter

    喜欢做些开源项目的朋友,相信有不少人都希望能把自己的项目发布到公共的中央仓库,如maven中央仓库,以供别人方便地集成使用.而使用了Android Studio的同学,应该也对gradle和jcent ...

  6. 百度DMLC分布式深度机器学习开源项目(简称“深盟”)上线了如xgboost(速度快效果好的Boosting模型)、CXXNET(极致的C++深度学习库)、Minerva(高效灵活的并行深度学习引擎)以及Parameter Server(一小时训练600T数据)等产品,在语音识别、OCR识别、人脸识别以及计算效率提升上发布了多个成熟产品。

    百度为何开源深度机器学习平台?   有一系列领先优势的百度却选择开源其深度机器学习平台,为何交底自己的核心技术?深思之下,却是在面对业界无奈时的远见之举.   5月20日,百度在github上开源了其 ...

  7. 发布开源项目到Jcenter

    前言 为了将阿里云短信开箱即用发布到Jcenter仓库,前前后后花费了1天半的时间,把端午节都搭进去了.终于今天收到了Jcenter的消息,自己发布的包被添加到了Jcenter仓库,也算给开源社区做了 ...

  8. 有趣的开源项目集结完毕,HelloGitHub 月刊第 63 期发布啦!

    兴趣是最好的老师,HelloGitHub 让你对编程感兴趣! 简介 分享 GitHub 上有趣.入门级的开源项目. 这里有实战项目.入门教程.黑科技.开源书籍.大厂开源项目等,涵盖多种编程语言 Pyt ...

  9. 一大波开发者福利来了,一份微软官方Github上发布的开源项目清单等你签收

    目录 微软Github开源项目入口 微软开源项目受欢迎程度排名 Visual Studio Code TypeScript RxJS .NET Core 基础类库 CNTK Microsoft cal ...

随机推荐

  1. 在执行java代码时,设置了断点,然后莫名的没执行完方法内的代码就结束了,此刻一般在出错处代码用try,catch包括起来

    在执行java代码时,设置了断点,然后莫名的没执行完方法内的代码就结束了,此刻一般在出错处代码用try,catch包括起来就能看到是什么异常了,记住try,catch语句的作用

  2. [react]react创建app,路由,mobx 全教程

    ​ 1.创建app, npx create-react-app my-app Cmd Copy 2.进入项目目录 cd my-app Cmd Copy 3.启用配置文件(默认是不开启配置文件的) ya ...

  3. python 安装模块报错 response.py", line 302, in _error_catcher

    python 安装模块报错 Exception:Traceback (most recent call last): File "/usr/share/python-wheels/urlli ...

  4. Linux(Centos)部署Jenkins,并配置Git生成Jar包进行发布部署

    需要先安装jdk.maven.git环境 jdk安装:https://www.cnblogs.com/pxblog/p/10512886.html maven安装:https://www.cnblog ...

  5. 【LeetCode】896. Monotonic Array 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  6. C. Hongcow Builds A Nation

    C. Hongcow Builds A Nation time limit per test 2 seconds memory limit per test 256 megabytes input s ...

  7. A. Points on Line

    A. Points on Line time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...

  8. 1067 - Combinations

    1067 - Combinations   PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 MB Giv ...

  9. 【操作系统】编程模拟FIFO,LRU,NUR,OPT页面置换算法

    #include<stdio.h> #include<stdlib.h> #include<time.h> #define random(x) (rand()%x) ...

  10. Reflection 基础知识(二)

    Proxy 定义 Proxy用于修改对象的某些行为,获取值,设置值等 let p = new Proxy(target, handler); target 用Proxy包装的目标对象(可以是任何类型的 ...