一、Cmake 常用语句

1.1 程序的编译和执行

源程序经过预处理、编译、汇编、链接步骤后,才能生成可执行程序。

  • 预处理:条件编译,头文件包含,宏替换的处理,刪除注释,生成.i文件。

gcc -E hello_world.c -o hello_world.i

  • 编译:将预处理后的文件转换成汇编语言,生成.s文件

gcc -S

  • 汇编:汇编变为目标代码(机器代码)生成.o的文件

gcc -c hello_world.s -o hello_world.o

  • 链接:连接目标代码,生成可执行程序

gcc hello.world.o -o hello_world

1.2 cmake

CMake是一种跨平台编译工具,比make更为高级,使用起来要方便得多。CMake主要是编写CMakeLists.txt文件,然后用cmake命令将CMakeLists.txt文件转化为make所需要的makefile文件,最后用make命令编译源码生成可执行程序或共享库(so(shared object))。

cmake  指向CMakeLists.txt所在的目录,例如cmake .. 表示CMakeLists.txt在当前目录的上一级目录。cmake后会生成很多编译的中间文件以及makefile文件。

cmake的特点:开源、跨平台、可扩展、简化编译构建过程和编译过程。

(1)cmake 变量

CMake支持简单的变量,它们或者是字符串,或者是字符串的列表。引用一个变量的语法是 ${VAR_NAME}

set(V 1 2 3)    # V的值是1 2 3
command(${V})   # 等价于command(1 2 3)

要把一个列表变量作为整体传递,只需要加上双引号即可:

command("${V}")   # 等价于command("1 2 3")

(2)cmake 实现原理

CMake包含一系列重要的概念抽象,包括目标(Targets)、生成器(Generators)、命令(Commands)等,这些命令均被实现为C++类。理解这些概念后才能编写高效的CMakeLists文件。

  • 源文件:对应了典型的C/C++源代码;
  • 目标:多个源文件联合成为目标,目标通常是可执行文件或者库;
  • 目录:表示源码树中的一个目录,常常包含一个CMakeLists.txt文件,一或多个目标与之关联;
  • 本地生成器(Local generator):每个目录有一个本地生成器,负责为此目录生成Makefiles,或者工程文件;
  • 全局生成器(Global generator):所有本地生成器共享一个全局生成器,后者负责监管构建过程,全局生成器由CMake本身创建并驱动。

CMake的执行开始时,会创建一个cmake对象并把命令行参数传递给它。cmake对象管理整体的配置过程,持有构建过程的全局信息(例如缓存值)。cmake会依据用户的选择来创建合适的全局生成器(VS、Makefiles等等),并把构建过程的控制权转交给全局生成器(调用configure和generate方法)。

全局生成器负责管理配置信息,并生成所有Makefiles/工程文件。一般情况下全局生成器把具体工作委托给本地生成器执行,全局生成器为每个目录创建一个本地生成器。

(3)目标

Makefile对象中存放的最重要的对象是目标(Targets),目标代表可执行文件、库、实用工具等。每个 add_library 、 add_executable 、 add_custom_target 命令都会创建一个目标。

# 创建一个静态库,包含两个源文件
add_library(foo STATIC foo1.c foo2.c)

1.3 cmake 常见语法

(1)cmake 版本号设置cmake_minimum_required


# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

(2)设置项目信息 project

# 项目信息
project (Demo1)

(3)生成目标 add_executable

# 指定生成目标
add_executable(Demo main.cc)# 指定多个源文件,生成目标
add_executable(Demo main.cc MathFunctions.cc)

aux_source_directory,该命令会查找指定目录下的所有源文件,然后将结果存进指定变量名。

# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成目标
add_executable(Demo ${DIR_SRCS})

(4)添加子目录add_subdirectory

add_subdirectory 指明本项目包含一个子目录 ,这样 子目录下的 CMakeLists.txt 文件和源代码也会被处理

# 如在主目录下有个子目录math,添加 math 子目录
add_subdirectory(math)

(5)指明可执行程序所需要的链接库  TARGET_LINK_LIBRARIES (设置要链接的库文件的名称)

语法:TARGET_LINK_LIBRARIES(targetlibrary1 <debug | optimized> library2 ..)

TARGET_LINK_LIBRARIES(myProject hello),连接libhello.so库
TARGET_LINK_LIBRARIES(myProject libhello.a)
TARGET_LINK_LIBRARIES(myProject libhello.so)

命令 target_link_libraries 指明可执行文件 Demo 需要连接一个名为 MathFunctions 的链接库

# 添加链接库
target_link_libraries(Demo MathFunctions)
  • 如果目标的头文件中包含了依赖的头文件(源文件间接包含),那么这里就是PUBLIC
  • 如果目标仅源文件中包含了依赖的头文件,那么这里就是PRIVATE
  • 如果目标的头文件包含依赖,但源文件未包含,那么这里就是INTERFACE

(6)设置变量 set


set(SRC_LIB "${CMAKE_SOURCE_DIR}/src/main/jnilibs")

定义了一个变量SRC_LIB,并且变量的值为${CMAKE_SOURCE_DIR}/src/main/jnilibs,其中CMAKE_SOURCE_DIR 是一个cmake内置变量,指定了CMakeLists.txt所在的目录

(7)输出信息 message

message( [STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR]"message to display" ...)
无) = 重要消息;STATUS = 非重要消息;WARNING = CMake 警告, 会继续执行;AUTHOR_WARNING = CMake 警告 (dev), 会继续执行;SEND_ERROR = CMake 错误, 继续执行,但是会跳过生成的步骤;FATAL_ERROR = CMake 错误, 终止所有处理过程;

(8)将自定义构建规则添加到生成的构建系统 add_custom_command

add_custom_command

  • 如果使用OUTPUT参数,需要在目标的构建中指定依赖于该OUTPUT
  • 如果使用TARGET参数,直接指定目标就可以了
add_custom_command(OUTPUT output1 [output2 ...]COMMAND command1 [ARGS] [args1...]``[COMMAND command2 [ARGS] [args2...] ...][MAIN_DEPENDENCY depend][DEPENDS [depends...]][BYPRODUCTS [files...]][IMPLICIT_DEPENDS <lang1> depend1[<lang2> depend2] ...][WORKING_DIRECTORY dir][COMMENT comment][DEPFILE depfile][JOB_POOL job_pool][VERBATIM] [APPEND] [USES_TERMINAL][COMMAND_EXPAND_LISTS])
add_custom_command(TARGET <target>PRE_BUILD | PRE_LINK | POST_BUILDCOMMAND command1 [ARGS] [args1...][COMMAND command2 [ARGS] [args2...] ...][BYPRODUCTS [files...]][WORKING_DIRECTORY dir][COMMENT comment][VERBATIM] [USES_TERMINAL])
  • OUTPUT:指定命令预期产生的输出文件。如果输出文件的名称是相对路径,即相对于当前的构建的源目录路径;
  • COMMAND:指定要在构建时执行的命令行;
  • DEPENDS:指定命令所依赖的文件;
  • COMMENT:在构建时执行命令之前显示给定消息;
  • WORKING_DIRECTORY:使用给定的当前工作目录执行命令。如果它是相对路径,它将相对于对应于当前源目录的构建树目录;
  • DEPFILE:为生成器指定一个.d depfile .d文件保存通常由自定义命令本身发出的依赖关系;
  • MAIN_DEPENDENCY:指定命令的主要输入源文件;
  • BYPRODUCTS:指定命令预期产生的文件。
cmake_minimum_required(VERSION 3.0)
project(test)add_custom_command(OUTPUT COPY_RESCOMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/config ${CMAKE_CURRENT_SOURCE_DIR}/etcCOMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/log.txt ${CMAKE_CURRENT_SOURCE_DIR}/etc)add_custom_target(CopyTask ALL DEPENDS COPY_RES)

(9)添加需要链接的库文件目录LINK_DIRECTORIES

link_directories(directory1 directory2 ...)

它相当g++命令的-L选项的作用,也相当于环境变量中增加LD_LIBRARY_PATH的路径的作用。

link_directories("/lib/directory/")

(10)LINK_LIBRARIES (添加需要链接的库文件路径,注意这里是全路径)

LINK_LIBRARIES("/opt/MATLAB/R2012a/bin/glnxa64/libeng.so")
LINK_LIBRARIES("/opt/MATLAB/R2012a/bin/glnxa64/libmx.so")

(11)添加宏定义,代码中控制编译add_definitions

cmake的宏定义分为全局宏定义和针对某个目标定义宏定义。

定义全局宏定义:

# 定义宏MACRO_NAME,注意前面的-D
add_definitions(-DMACRO_NAME)
# 赋值
add_definitions(-DMACRO_NAME=${value})

应用举例:

在工程CMakeLists.txt 中,使用add_definitions()函数控制代码的开启和关闭。

option(TEST_DEBUG "option for debug" OFF)
if (TEST_DEBUG) add_definitions(-DTEST_DEBUG)
endif(TEST_DEBUG)

option用法  /*TEST_DEBUG为编译开关,中间的字符串为描述信息,ON/OFF 为默认选项*/

运行构建项目的时候可以添加参数控制宏的开启和关闭

cmake     -DTEST_DEBUG = on ..   #打开

源码中使用该宏进行控制条件编译

#ifdef TEST_DEBUG
...
...
#else
...
#endif

option: 为选项开关

针对某个目标添加宏定义:

# 仅仅能用于 add_executable() 或 add_library() 添加的目标
# 格式:
target_compile_definitions(<target># PUBLIC、INTERFACE可以将宏定义传递给target的PUBLIC、INTERFACE条目<INTERFACE|PUBLIC|PRIVATE> [items1...][<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
# 示例:
target_compile_definitions(hello PRIVATE A=1 B=0)
# 你也可以直接设置目标属性  COMPILE_DEFINITIONS

应用举例


target_compile_definitions(目标进程PUBLIC宏名称
)

(12)set_target_properties

设置目标的一些属性来改变它们构建的方式。

set_target_properties(target1 target2 ...PROPERTIES prop1 value1prop2 value2 ...)

(13)target_compile_definitions

为目标增加编译定义。

target_compile_definitions(<target><INTERFACE|PUBLIC|PRIVATE> [items1...][<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

(14) target_include_directories

将给定目录加给编译器搜索到的包含文件

target_include_directories(<target> [SYSTEM] [BEFORE]<INTERFACE|PUBLIC|PRIVATE> [items1...][<INTERFACE|PUBLIC|PRIVATE> [items2...] ...]

BEFORE or AFTER 可以加在前面或者后面. 如果设定 SYSTEM 选项 编译器认定为系统包含目录。

(15) find_package引入外部依赖包

https://zhuanlan.zhihu.com/p/97369704?utm_source=wechat_session

(16)add_compile_options

设置编译选项可以通过add_compile_options命令,也可以通过set命令修改CMAKE_CXX_FLAGSCMAKE_C_FLAGS。

add_compile_options命令添加的编译选项是针对所有编译器的(包括c和c++编译器),而set命令设置CMAKE_C_FLAGSCMAKE_CXX_FLAGS变量则是分别只针对c和c++编译器的。

#判断编译器类型,如果是gcc编译器,则在编译选项中加入c++11支持
if(CMAKE_COMPILER_IS_GNUCXX)add_compile_options(-std=c++11)message(STATUS "optional:-std=c++11")
endif(CMAKE_COMPILER_IS_GNUCXX)

只针对c++编译器添加这个option。

#判断编译器类型,如果是gcc编译器,则在编译选项中加入c++11支持
if(CMAKE_COMPILER_IS_GNUCXX)set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")message(STATUS "optional:-std=c++11")
endif(CMAKE_COMPILER_IS_GNUCXX)

(17)list 列表操作

list(LENGTH <list> <output variable>)
list(GET <list> <element index> [<element index> ...]<output variable>)
list(APPEND <list> [<element> ...])
list(FIND <list> <value> <output variable>)
list(INSERT <list> <element_index> <element> [<element> ...])
list(REMOVE_ITEM <list> <value> [<value> ...])
list(REMOVE_AT <list> <index> [<index> ...])
list(REMOVE_DUPLICATES <list>)
list(REVERSE <list>)
list(SORT <list>)

说明:

LENGTH will return a given list’s length.#返回列表的长度

GET will return list of elements specified by indices from the list.#读取列表指定索引

APPEND will append elements to the list.  #将子元素追加到列表

FIND will return the index of the element specified in the list or -1 if it wasn’t found.

INSERT will insert elements to the list to the specified location.

REMOVE_AT and REMOVE_ITEM will remove items from the list. The difference is that REMOVE_ITEM will remove the given items, while REMOVE_AT will remove the items at the given indices.

REMOVE_DUPLICATES will remove duplicated items in the list.

REVERSE reverses the contents of the list in-place.

SORT sorts the list in-place alphabetically.

其他参考:Cmake命令之list介绍 - 百度文库

(18)file

file GLOB命令主要用于匹配规则在指定的目录内匹配到所需要的文件,命令行格式:

file(GLOB <variable> [LIST_DIRECTORIES true[false] [RELATIVE <path> ] [CONFIGURE_DEPENDS] [<globbing-expression> ...])

如:寻找当前路径下的cpp文件,且返回的结果中为/public/home的相对路径,


file(GLOB TEST_RESULT LIST_DIRECT true RELATIVE /public/home *.cpp)
message("--------TEST_RESULT:  ${TEST_RESULT}")

获取指定路径下全部源文件,按照绝对路径的形式

FILE (GLOB_RECURSE PROJECT_SRC ${PROJECT_SOURCE_DIR}/*.hpp ${PROJECT_SOURCE_DIR}/*.cpp)

(19)install

install用于指定在安装时运行的规则。它可以用来安装很多内容,可以包括目标二进制、动态库、静态库以及文件、目录、脚本等

install(TARGETS <target>... [...])
install({FILES | PROGRAMS} <file>... [...])
install(DIRECTORY <dir>... [...])
install(SCRIPT <file> [...])
install(CODE <code> [...])
install(EXPORT <export-name> [...])

如:

INSTALL(TARGETS myrun mylib mystaticlibRUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)

可执行二进制myrun安装到${CMAKE_INSTALL_BINDIR}目录,动态库libmylib.so安装到${CMAKE_INSTALL_LIBDIR}目录,静态库libmystaticlib.a安装到${CMAKE_INSTALL_LIBDIR}目录。

二、Cmake 流程控制语句

CMake支持条件、循环控制结构,同时支持子过程(macro、function)

2.1 if-else-endif

if (condition)command1
else(condition)command2
endif(condition)

使用 elseif语句

if(MSVC80)#...
elseif(MSVC90)#...
elseif(APPLE)#...
endif()

判断条件:

2.2  foreach

foreach (item  list)# do something with item
endforeach (item)

此命令用于迭代一个列表,第一个参数是每次迭代使用变量的名称,其余参数为被迭代的列表。

2.3 while

while(${COUNT} LESS 2000)set(TASK_COUNT, ${COUNT})
endwhile()

三、Cmake 实战

3.1 搭建cmake 环境

使用阿里云 centos 8.0 环境

(1)安装cmake

yum install cmake
查看安装情况:

(2)安装gcc-c++

yum install gcc-c++
 

3.2 基础实例

(1)构建c++ 工程

#include <iostream>using namespace std;int main() {return 0;
}

(2)需要在同一目录下放置CMakeLists.txt文件,编写如下内容:

# 需要最小的CMake版本
cmake_minimum_required(VERSION 3.3)
# 工程的名称,会作为MSVS的Workspace的名字
project(intellij_taste)# 全局变量:CMAKE_SOURCE_DIR CMake的起始目录,即源码的根目录
# 全局变量:PROJECT_NAME 工程的名称
# 全局变量:PROJECT_SOURCE_DIR 工程的源码根目录的完整路径# 全局变量:构建输出目录。默认的,对于内部构建,此变量的值等于CMAKE_SOURCE_DIR;否则等于构建树的根目录
set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/bin)  # ${}语法用于引用变量 自动创建bin目录
# 全局变量:可执行文件的输出路径
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
# 全局变量:库文件的输出路径
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR})
# 设置头文件位置
include_directories("${PROJECT_SOURCE_DIR}")
# 设置C++标志位
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
# 设置源文件集合
set(SOURCE_FILES main.cpp)
# 添加需要构建的可执行文件,第二个以及后续参数是用于构建此文件的源码文件
add_executable(intellij_taste ${SOURCE_FILES})

(3)执行cmake

# 创建一个build子目录作为构建树
mkdir build
cd build
cmake .. # 在build/bin子目录中生成可执行文件:
# cmake --build <dir> [options] [-- [native-options]]
cmake --build build -- -j3  # --表示把其余选项传递给底层构建工具# 注意,亦可使用底层构建系统,例如make命令或者MSVC的IDE
cd build
make -j3

四、Cmake 生成VS工程

4.1 基本语法

(1)source_group

定义一组源文件到项目文件中. 主要用来配置Visual Studio中的文件标签. 任何被列出的或者与正则表达式匹配的文件都将被放入组中. 如

  source_group(name [REGULAR_EXPRESSION regex] [FILES src1 src2 ...])

应用举例:

  source_group(test\\vs项目文件集名称 REGULAR_EXPRESSION "代码目录/.+\.(h|inc|cc)") 

参考文献:

【1】Cmake知识----编写CMakeLists.txt文件编译C/C++程序 : Cmake知识----编写CMakeLists.txt文件编译C/C++程序 - horsetail - 博客园

【2】Makefile和Cmake的联系与区别 : Makefile和Cmake的联系与区别_hjxu2016的博客-CSDN博客_cmake和makefile区别

【3】CMake 入门实战(精):CMake 入门实战(精)_起风了-CSDN博客_cmake 入门

【4】CMake之message()函数的使用和打印变量值: CMake之message()函数的使用和打印变量值_斧冰-CSDN博客_cmake message

【5】Cmake 内置变量: Cmake 内置变量_测试-CSDN博客

【6】Cmake官网: Documentation | CMake

【7】【CMake】cmake的add_custom_command和add_custom_target指令: 【CMake】cmake的add_custom_command和add_custom_target指令_Yngz_Miao的博客-CSDN博客_add_custom_command

【8】CMake 添加需要链接的库文件目录LINK_DIRECTORIES:CMake 添加需要链接的库文件目录LINK_DIRECTORIES | 浩瀚宇宙 灿烂星空

【9】link_directories, LINK_LIBRARIES, target_link_libraries使用总结: link_directories, LINK_LIBRARIES, target_link_libraries使用总结_w_w的专栏-CSDN博客

【10】linux 下 g++编译程序时,-I(大写i) 与-L(大写l)-l(小写l) 的作用: linux 下 g++编译程序时,-I(大写i) 与-L(大写l)-l(小写l) 的作用_月落及晨曦-CSDN博客

gcc -I(大写的i),-L(大写L)和-l(小写的L)详解:gcc -I(大写的i),-L(大写L)和-l(小写的L)详解_TMD_MCU的博客-CSDN博客

【11】CMAKE 中add_definitions的用法: CMAKE 中add_definitions的用法_邦戈邦戈栗子的博客-CSDN博客

【12】add_library,target_link_libraries,set_target_properties,target_link_libraries使用联系: add_library,target_link_libraries,set_target_properties,target_link_libraries使用联系_michaelhan3的博客-CSDN博客

【13】cmake CMakeLists.txt 命令 add_compile_options、add_definitions、target_compile_definitions、build_command: cmake CMakeLists.txt 命令 add_compile_options、add_definitions、target_compile_definitions、build_command_whatday的专栏-CSDN博客

【14】CMake-scope-PRIVATE-PUBLIC-INTERFACE: CMake-scope-PRIVATE-PUBLIC-INTERFACE_行走-CSDN博客

【15】cmake的四个命令:add_compile_options、add_definitions、target_compile_definitions、build_command...: cmake的四个命令:add_compile_options、add_definitions、target_compile_definitions、build_command..._DragonWar%的博客-CSDN博客

【16】CMake学习笔记:绿色记忆:CMake学习笔记

【17】CMake 入门1/5:基于阿里云 ECS搭建体验环境: CMake 入门1/5:基于阿里云 ECS搭建体验环境_weixin_33947521的博客-CSDN博客

【18】cmake:设置编译选项的讲究(add_compile_options和CMAKE_CXX_FLAGS的区别)_10km的博客-CSDN博客_add_compile_options

【19】CMAKE 批量获取目录下指定类型文件并转换为相对路径_黑色低级高中生的博客-CSDN博客

Cmake学习实战-基础篇相关推荐

  1. Redis学习笔记①基础篇_Redis快速入门

    若文章内容或图片失效,请留言反馈.部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 资料链接:https://pan.baidu.com/s/1189u6u4icQYHg_9_7ovWmA( ...

  2. SpringBoot2零基础到项目实战-基础篇

    springboot2零基础到项目实战-基础篇 课程内容说明 课程单元 学习目标 基础篇 能够创建SpringBoot工程 基于SpringBoot实现ssm/ssmp整合 应用篇 能够掌握Sprin ...

  3. Lua与c++交互实战基础篇-夏曹俊-专题视频课程

    Lua与c++交互实战基础篇-10018人已学习 课程介绍         本课程从实战角度讲解了流行的高性能脚本Lua与c++的联合开发,这套方案已经被大量的对性能由要求的系统使用,成为了高性能脚本 ...

  4. Xamarin.Forms开发实战基础篇大学霸内部资料

    Xamarin.Forms开发实战基础篇大学霸内部资料 介绍:本教程是国内第一本Xamarin.Forms开发专向教程.本教程针对Xamarin.Forms初学用户,全面细致的讲解Xmarin.For ...

  5. ASP.NET Google Maps Javascript API V3 实战基础篇一获取和设置事件处理程序中的属性...

    ASP.NET Google Maps Javascript API V3 实战基础篇一获取和设置事件处理程序中的属性 <%@ Page Language="C#" Auto ...

  6. Nginx实战基础篇一 源码包编译安装部署web服务器

    Nginx实战基础篇一 源码包编译安装部署web服务器 版权声明: 本文遵循"署名非商业性使用相同方式共享 2.5 中国大陆"协议 您可以自由复制.发行.展览.表演.放映.广播或通 ...

  7. ASP.NET Google Maps Javascript API V3 实战基础篇一检测用户位置

    ASP.NET Google Maps Javascript API V3 实战基础篇一检测用户位置 对于一些基本的东西,google maps JavaScript api v3 文档已经讲解得足够 ...

  8. Nginx实战基础篇六 通过源码包编译安装部署LNMP搭建Discuz论坛

    Nginx实战基础篇六 通过源码包编译安装部署LNMP搭建Discuz论坛 版权声明: 本文遵循"署名非商业性使用相同方式共享 2.5 中国大陆"协议 您可以自由复制.发行.展览. ...

  9. MySQL学习笔记-基础篇1

    MySQL 学习笔记–基础篇1 目录 MySQL 学习笔记--基础篇1 1. 数据库概述与MySQL安装 1.1 数据库概述 1.1.1 为什么要使用数据库 1.2 数据库与数据库管理系统 1.2.1 ...

最新文章

  1. 说说 JAVA 代理模式
  2. 基于灰度变换的图像增强
  3. [Codeforces702F]T-Shirts——非旋转treap+贪心
  4. mysql秒级平滑_DDM实践:数据库秒级平滑扩容方案
  5. java集合框架05——ArrayList和LinkedList的区别
  6. Log4j文件配置教程大全
  7. 圆柱与平面接触宽度_好烦!这个建筑高大斜圆柱真难施工!别怕!学会这种工法就不难了...
  8. 我学习的自定义ASP.NET分页控件
  9. 【Linux学习】vim编辑器的使用
  10. 实例讲解统计学基础知识(1):统计学基础概念
  11. Spark机器学习实例
  12. 【前端】前端学习课程及内容概述
  13. Docker官方文档翻译1
  14. SpringBoot项目启动异常:Field settlementMissService in...Service required a single bean, but 2 were found:
  15. 谷歌html弹出ie页面,如何从谷歌跳转IE,打开指定的网址
  16. [转载]【职场新人必看】领导谆谆寄语
  17. 大学C语言系统作业,南昌大学作业答疑系统c语言答案
  18. 使用WICleanup清理Windows Installer 冗余文件
  19. 网站如何诊断,完整的网站诊断方法!
  20. 计算机音乐我还是曾经那个少年,我还是曾经的那个少年什么歌曲?是谁唱的?求科普!...

热门文章

  1. ns3 Traffic Control Layer解读
  2. mt2503 在MMI版本实现AT+CPBF
  3. SKU与SPU的区别
  4. 用于时间机器备份的文件服务器地址,一日一技 | 如何解决时间机器在 NAS 上创建备份失败的问题?...
  5. 拼多多api(json格式爬虫采集)
  6. win7打不开chm格式文件
  7. 【小罗的hdlbits刷题笔记4】从lemming4中的有限状态机debug过程中的一些感悟
  8. 手机gps信号弱 服务器设置,手机GPS服务器设置
  9. Samba服务器搭建,win10拒绝访问解决方法
  10. codeblocks 注释取消红色下划线