头文件字符串制作与使用的问题
编译依赖多个头文件的源文件时,找不到头文件是一个再常见不过的问题。配置头文件路径却常常让人头疼。以前没有深入的想这个问题,在很多 IDE 中都是依次添加每个头文件所在目录,花费了大量的时间。
这个问题可以划分为两个子问题:
- 找到包含头文件的目录路径
- 以路径制作固定格式字符串
第一个问题的解决示例如下:
find ./ -name '*.h' -exec dirname {} \; | sort -u > inc_dir
find 首先在当前目录中以万用符匹配后缀名为 .h 的文件,然后依次对每个找到的文件执行 dirname,移除路径中的文件名,然后将输出通过管道发送到 sort 命令作为输入,进行排序并合并。
上述命令的效率不高,这很大程度与 find 中 -exec 的执行方式有关。
-exec command ; 此种方式中,使用找到的每个文件路径代替 {},以该路径 command 的参数来执行 command,简单讲就是找到一个执行一次,程序执行次数等于匹配到的文件数目,匹配文件很多时此方式执行时间很长。
-exec command {} + 此种方式中,匹配到的每个文件路径追加到命令行尾,当命令行过长则分多次执行。这种方式中,command 命令的执行次数将会少于匹配到的文件数目。匹配到的文件数据很多时,这种方式执行时间很短。
下面是与之相关的测试数据 :
[longyu@debian:23:31:21] rt-thread-master $ /usr/bin/time -v find ./ -name '*.h' -exec dirname {} \; | sort -u > inc_file
Command being timed: "find ./ -name *.h -exec dirname {} ;"
User time (seconds): 0.08
System time (seconds): 0.40
Percent of CPU this job got: 14%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:03.26
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 2932
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 620686
Voluntary context switches: 12663
Involuntary context switches: 6386
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
[longyu@debian:23:31:35] rt-thread-master $ /usr/bin/time -v find ./ -name '*.h' -exec dirname {} \+ | sort -u > inc_file
Command being timed: "find ./ -name *.h -exec dirname {} +"
User time (seconds): 0.02
System time (seconds): 0.03
Percent of CPU this job got: 89%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.06
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 2920
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 789
Voluntary context switches: 7
Involuntary context switches: 10
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
[longyu@debian:23:31:52] rt-thread-master $ /usr/bin/time find ./ -name '*.h' | xargs dirname | sort -u > inc_file
0.02user 0.02system 0:00.04elapsed 97%CPU (0avgtext+0avgdata 2928maxresident)k
0inputs+0outputs (0major+258minor)pagefaults 0swaps
[longyu@debian:23:32:07] rt-thread-master $ /usr/bin/time -v find ./ -name '*.h' | xargs dirname | sort -u > inc_file
Command being timed: "find ./ -name *.h"
User time (seconds): 0.04
System time (seconds): 0.03
Percent of CPU this job got: 96%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.07
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 3024
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 262
Voluntary context switches: 1
Involuntary context switches: 8
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
[longyu@debian:23:32:15] rt-thread-master $
上述测试仅仅测了 find 命令的执行效率。从数据中可以看出,-exec command ; 这种方式下程序从系统缓存中读取了几十万页的数据,频繁的访问内存带来更高的负载。同时这种方式下程序执行了近2万次上下文切换,任务切换中的保存与恢复现场也提高了负载,结果就是程序的执行时间变得很长。
反观,剩余两种方式仅仅从系统缓存中读取了几百页的数据,同时进行了特别少的任务切换,执行时间大幅度消减。
同时需要注意对内存的占用情况。-exec 的两种方式内存占用大致相同,管道处理方式占用了更多的内存。
第二个问题的解决示例如下 :
sed 's/\.\/\(.*\)/{"$PROJECT:\/\1"}/g' inc_file
部分输出如下:
{"$PROJECT:/libcpu/ppc/ppc405/include"}
{"$PROJECT:/libcpu/ppc/ppc405/include/asm"}
{"$PROJECT:/libcpu/rx"}
{"$PROJECT:/libcpu/sim/win32"}
{"$PROJECT:/libcpu/unicore32/sep6200"}
{"$PROJECT:/libcpu/xilinx/microblaze"}
{"$PROJECT:/src"}
使用子串匹配来进行替换,制作字符串,将该字符串复制到 IDE 中即可使用。
另一种示例如下 :
INCLUDE=$(sed 's/\.\/\(.*\)$/-I"\1"/g' inc_file)
INCLUDE 变量部分内容如下 :
-I"tools/kconfig-frontends/frontends/qconf" -I"tools/kconfig-frontends/libs/lxdialog" -I"tools/kconfig-frontends/libs/parser"