1.5分钟掌握cmake(19): 使用 SYSTEM 关键字忽略三方库头文件的源码编译警告
2.System.out.println()åSystem.out.println(" ");å¾åºå«ï¼
3.system在C语言里是什么意思
4.c语言system("cls")怎么导入一个项目?
5.javaï¼System.out.println();
5分钟掌握cmake(19): 使用 SYSTEM 关键字忽略三方库头文件的编译警告
1年前,@大缺弦 在 CMake 官方仓库中为 add_subdirectory() 增加了 SYSTEM 关键字 (FetchContent_Declare 也加了,源码 不过我还没用过这个函数),源码 并在 CMake 3. 版本中正式发布。源码 本文提供一个简单的源码例子, 展示个人对 add_subdirectory(xxx SYSTEM) 的源码扫描模组源码理解。
2. 复现工程代码
2.1 目录结构
有如下的源码目录结构:在自己的工程example 下, 引入了第三方的源码工程 hello: 可以是完全基于源代码的三方工程, 也可以是源码头文件 + 库文件的形式, 异或是源码 header-only 的三方库。 即:
hello 子目录是源码别人工程的源码:
或如下的目录结构: hello 子目录是头文件 + 预编译好的库 + CMakeLists.txt:
或者 header-only 形式:
无论是哪种形式,hello/hello.h 这一头文件,源码 都会被自己的源码源代码 test_hello.cpp 包含, 从而参与到 example 工程的源码网店共享系统源码构建中。 而 example 工程可能使用了和 hello 不同的源码 "treat warning as errors" 设定, 会导致 hello.h 在 hello 工程中不会编译报错, 但在 example 工程中就会报错了。
我们的预期是:hello.h 在参与到 example/test_hello.cpp 的预处理过程时, 不要使用 example/CMakeLists.txt 里的严格的编译报错设定, 放宽它的编译报错等级; 同时保持 test_hello.cpp 自身的 cpp 代码, 仍然是被严格处理的。
2.2 头文件 hello.h 内容
2.3 test_hello.cpp 内容
2.4 根目录 CMakeLists.txt 内容
2.5 完整工程
github.com/zchrissirhcz...
3. Linux下的运行结果和分析
3.1 运行结果: 使用 SYSTEM 后, 头文件 hello/hello.h 不再触发编译报错
3.2 检查 compile_commands.json 里的具体编译命令, -I 被 -isystem 替代
3.3 -I 和 -isystem 的区别是什么? man gcc 可以知道, 被 -isystem 指定的目录, 会被当作标准系统目录对待:
而人们提到的
-isystem
会忽略自行在 makefile/CMakeLists.txt 中指定的 warning, 可以在 gcc 在线文档中找到:
3.4include_directories() 和 target_include_directories() 也可以用 SYSTEM 在 How to suppress GCC warnings from library headers? 问答中, 有人提到可以在 include_directories() 中指定 SYSTEM 关键字来抑制编译警告:
查看文档得到验证:
实际上,
target_include_directories()
也可以用
SYSTEM
关键字, 也是kd底背离源码生成
-isystem
的编译命令:
查看 compile_commands.json 验证:
4. 使用 -isystem 的进一步探讨
4.1 -Wsystem-headers 开启 system headers 的 warning man gcc 可以知道, 提供的 -Wsystem-headers 编译选项, 是把 system headers 里的警告开启, 也就是说当你用 -isystem 指定了一个三方库路径后, 如果想开启它里面的 warning, 可以用 -I 替代 -isystem 来开启 warning, 也可以用 -Wsystem-headers 来开启 warning:
4.2 使用 -fsystem-headers 的提议 (尚未实现)
在 Bug - Create hybrid of -I and -isystem that is like -I but deactivates warnings 中有人提到, 人们使用 -isystem /some/path 替代 -I /some/path, 有点滥用系统头文件路径的问题, 考虑让 gcc 增加 -fsystem-headers 参数, 进而使用:
来让/some/path 被搜索时忽略警告。 不过这个 feature 尚未实现。
5. MSVC 下的结果
MSVC 使用/I, 和 GCC 的内核源码阅读工具 -I 对应; MSVC 使用 /externel:W0, 和 GCC 里的 -isystem 对应。
作为实验, 先前-Werror=shadow 的写法, 在 MSVC 下要更换为:
6. 总结
CMake 中, 有如下几个命令, 都可以使用SYSTEM 关键字, 使得被添加的头文件搜索目录中, 头文件里的 warning 完全被编译器忽略:
上述这些 cmake 命令, 是映射-I dir 为 -isystem dir, 根据 GCC 文档, -isystem 指定的 dir 被当作标准系统头文件目录:
由于编译器本身忽略了-isystem 指定目录中的警告, 那么开发者在 CMakeLists.txt 里指定的 treat warnings as errors 的设定, 由于没捕获到这些目录里的 waring, 因而不会触发编译报错。实体映射源码 这是一种避免陷入修改第三方库头文件源码的方法, 它仅对于头文件有效, 对于 add_subdirectories() 引入的源代码文件 (.c/.cpp) 不起作用。
在 GCC 和 MSVC 下,SYSTEM 关键字都起作用。
7. References
本文使用 Zhihu On VSCode 创作并发布
System.out.println()åSystem.out.println(" ");å¾åºå«ï¼
çä¸å®çæºä»£ç ä½ åºæ¬å°±ç解äº// System.out.println() çæºç public void println() {
newLine(); // æ¢è¡ï¼ä½ å¯ä»¥ç解为æå°"\r\n"
}
public void println(String paramString) {
synchronized (this) {
print(paramString); // æå°å符串ï¼ä¸ä¸»å¨æ¢è¡ï¼
newLine(); // æ¢è¡
}
}
System.out.println()åç¬ä½¿ç¨åºæ¬é½æ¯ä¸ºäºæçï¼æååå 容éå¼æè æå°ç¹å®å½¢ç¶çå¾æ¡çã
æ¯å¦ä¸é¢è¿æ ·æè æå°è±å½¢å¾æ¡
System.out.println("ä½ å¥½ï¼");System.out.println();
System.out.println(" å¾é«å ´â¦â¦");
System.out.println(" "); è¾åºç©ºæ ¼å¹¶æ¢è¡ï¼ä¸æ¶æ³ä¸èµ·ä»ä¹ä½¿ç¨åºæ¯ã
system在C语言里是什么意思
system()函数功能强大,很多人用却对它的原理知之甚少先看linux版system函数的源码:#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>
int system(const char * cmdstring)
{
pid_t pid;
int status;
if(cmdstring == NULL){
return (1);
}
if((pid = fork())<0){
status = -1;
}
else if(pid = 0){
execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
-exit(); //子进程正常执行则不会执行此语句
}
else{
while(waitpid(pid, &status, 0) < 0){
if(errno != EINTER){
status = -1;
break;
}
}
}
return status;
}
分析一下原理估计就能看懂了:
当system接受的命令为NULL时直接返回,否则fork出一个子进程,因为fork在两个进程:父进程和子进程中都返回,这里要检查返回的pid,fork在子进程中返回0,在父进程中返回子进程的pid,父进程使用waitpid等待子进程结束,子进程则是调用execl来启动一个程序代替自己,execl("/bin/sh", "sh", "-c", cmdstring, (char*)0)是调用shell,这个shell的路径是/bin/sh,后面的字符串都是参数,然后子进程就变成了一个shell进程,这个shell的参数是cmdstring,就是system接受的参数。在windows中的shell是command,想必大家很熟悉shell接受命令之后做的事了。
再解释下fork的原理:当一个进程A调用fork时,系统内核创建一个新的进程B,并将A的内存映像复制到B的进程空间中,因为A和B是一样的,那么他们怎么知道自己是父进程还是子进程呢,看fork的返回值就知道,上面也说了fork在子进程中返回0,在父进程中返回子进程的pid。
windows中的情况也类似,就是execl换了个又臭又长的名字,参数名也换的看了让人发晕的,我在MSDN中找到了原型,给大家看看:
HINSTANCE ShellExecute(
HWND hwnd,
LPCTSTR lpVerb,
LPCTSTR lpFile,
LPCTSTR lpParameters,
LPCTSTR lpDirectory,
INT nShowCmd
);
用法见下:
ShellExecute(NULL, "open", "c:\\a.reg", NULL, NULL, SW_SHOWNORMAL);
你也许会奇怪 ShellExecute中有个用来传递父进程环境变量的参数 lpDirectory,linux中的execl却没有,这是因为execl是编译器的函数(在一定程度上隐藏具体系统实现),在linux中它会接着产生一个linux系统的调用 execve, 原型见下:
int execve(const char * file,const char **argv,const char **envp);
看到这里就会明白为什么system()会接受父进程的环境变量,但是用system改变环境变量后,system一返回主函数还是没变。原因从system的实现可以看到,它是通过产生新进程实现的,从我的分析中可以看到父进程和子进程间没有进程通信,子进程自然改变不了父进程的环境变量。
使用了system函数就能执行dos指令。
#include <stdio.h>
#include <stdlib.h>
xiaoyu()
{
char *a;
int n=0;
FILE *f;
f=fopen("file.bat","w+");/*新建一个批处理*/
if(f==NULL)
exit(1);
a="echo"; /*DOS命令*/
for(n=;n<=;n++)/*大写A-Z*/
fprintf(f,"%s %c\n",a,n);/*利用ASCII码输出A-Z,写出批处理*/
fclose(f);
system("file.bat");/*运行批处理*/
}
main()
{
char *string;
xiaoyu();
string="echo C语言的system函数\n";/*输出中文*/
system(string);
system("pause");/*程序暂停*/
}
C中可以使用DOS命令,以后编程通过调用DOS命令很多操作就简单多了。
c语言system("cls")怎么导入一个项目?
在C语言中,system("cls")是用于清除控制台窗口内容的命令。要导入这个命令到一个C语言项目中,你需要遵循以下步骤:创建一个新的C语言项目或打开现有的C语言项目。
在你的C源代码文件中,添加#include <stdlib.h>这一行,以便包含stdlib.h头文件,该头文件中包含了system函数的声明。
在需要清除控制台窗口内容的地方调用system("cls")命令。这通常在你希望清屏的地方,例如在控制台程序的特定位置或菜单切换等操作之前。
确保你的项目的编译器支持该命令。大多数主流的C语言编译器都支持system函数以及cls命令。然而,一些非标准的或特定平台的编译器可能不支持该命令。
构建和运行你的项目,以查看system("cls")命令的效果。当你调用该命令时,控制台窗口的内容将被清除。
请注意,system("cls")命令在不同的操作系统和平台上可能会有不同的效果,因此在跨平台的项目中需要谨慎使用。此外,清除控制台窗口内容的需求可能因项目的特定要求而异,你也可以使用其他方法来实现清屏效果,如使用特定的库函数或控制台操作。
javaï¼System.out.println();
outæ¯Systemæä¾çç¨äºæ åè¾åºçæµï¼å¨æ²¡æéå®åçæ åµä¸ï¼ä¼ç´æ¥æå°å°ç»ç«¯ï¼èprintlnè¿ä¸ªæ¹å¼å®é ä¸æ¯PrintStreamç±»æä¾çåè½
éå®åé误è¾åºå¨jdkä¸æä¸æ®µè¯´æï¼
é常ï¼æ¤æµå¯¹åºäºæ¾ç¤ºå¨è¾åºæè ç±ä¸»æºç¯å¢æç¨æ·æå®çå¦ä¸ä¸ªè¾åºç®æ ãæç §æ¯ä¾ï¼æ¤è¾åºæµç¨äºæ¾ç¤ºé误æ¶æ¯ï¼æè æ¾ç¤ºé£äºå³ä½¿ç¨æ·è¾åºæµï¼åé out çå¼ï¼å·²ç»éå®åå°é常ä¸è¢«è¿ç»çè§çæä¸æ件æå ¶ä»ç®æ ï¼ä¹åºè¯¥ç«å»å¼èµ·ç¨æ·æ³¨æçå ¶ä»ä¿¡æ¯ã