您的位置:首页 > 运维架构 > Linux

linux 下 C 编程和make的方法 ( 六:补充 关于搭窝)

2012-11-11 23:13 591 查看
前面堆了一堆代码,说件让刚码过的朋友吐血的事,就上面这些代码我没有写一行,除了一些修改,整体就是COPY。从哪COPY来的,后面会说。先谈搭窝。

这事得从资源利用说起。我说了。大家的智商都差不多,你想做的更好,就得利用好你的脑袋的资源聚焦在一点上。有经验的老鸟能处理大项目,没经验的菜鸟,一 碰到复杂点点的,就完了。差异除了老鸟有知识技术方面的积累外,还有工作方法的经验。复杂的东西,抽丝剥茧,分成模块,集中注意力,盯住当前的目标。系统 明确,模块明确,目标明确。老鸟,一天搞一点,但是每天都有积累,汇总起来就OK。

因此,对于菜鸟而言,在你没学到广泛的知识前(这得花时间,毕竟你耳朵根子没有个USB口),集中你当前要解决的问题,这最重要的。尽可能把要面对的问 题,切得足够小。这还不够。还要最短时间内,能验证问题是否解决了。你可以把有些事情切出去,拖后处理,但当前的行为,要尽快验证。

所以,搭窝对于新手,是必须要。10个函数,2个C文件,洋洋洒洒的写完,才编译,好嘛,错误填满整个屏幕都不够,这也太打击你积极性了。

不过,我也不能每次介绍新模块时,都贴上 cd .. mkdir ..等等东西。怎么办呢?这里给了一个弱智版的脚本文件。用于自动生成模块目录,和生成对应模块文件。包括.h包括.c。包括测试文件。弱智版的我觉得好 啊,至少你们能看得懂。而且,没有必要搞那么复杂,我当然希望各位能理解configure文件的内部每个操作。但是这得解释太多东西。不如一步步来。

先说下,弱智版的自动生成模块的脚本怎么用。

有几个参数。

第一个参数必须要有,是表示模块名的。由这个模块,会自动创建目录。如果目录已经存在则会提示已经存在。或无法创建,比如有同名的文件在当前目录下。

第二个参数可以选择,目前有 -f -t两个。后面要对应跟上文件名。

-f 是你需要给模块module目录下自动生成src/a.c 和inc/a.h。并添加些基本代码。如下操作

1
$./create_module.sh
module -f a
-t 是自动生成测试文件,但是测试文件总要至少针对一个文件进行测试(别吐,目前也只能添加对一个文件进行测试的基本代码)。因此 -t有两个参数

1
$./create_module.sh
module -t b a
此时会在src/下自动生成一个test_b_main.c,而且会自动加上 #include "a.h"这类的代码。

需要注意,如果已经有对应文件存在,会提示,是否覆盖。这里没有追加的代码,毕竟弱智版的,我不想一下把脚本写的太多。目前已经够弱智的了。

对于前面那些搭窝的工作。你可以如下操作。

1
$./create_module.sh
data_struct -f ds_tree -t ds_tree ds_tree
这和

1
$./create_module.sh
data_struct -t ds_tree ds_tree -f ds_tree
你也可以尝试如下命令,换个测试名字

1
$./create_module.sh
data_struct -f ds_tree -t ds_tree ds
当然你也可以

1
$./create_module.sh
data_struct -t ds_tree ds
2
$./create_module.sh
data_struct -f ds_tree
上面两个命令没有顺序。都会检测目录是否存在,是否需要创建。

此时生成的是test_ds_main.c文件,在src/下。

清单如下。

001
#!/bin/bash
002
MODULE_NAME=$1
003
004
SRC_DIR_NAME=src
005
INC_DIR_NAME=inc
006
BIN_DIR_NAME=bin
007
OBJ_DIR_NAME=obj
008
C_FILE_SUFFIX=.c
009
H_FILE_SUFFIX=.h
010
TEST_FILE_SUFFIX=.t
011
CREATE_FILE_FLAG=-f
012
CREATE_TEST_FILE_FLAG=-t
013
OVERWRITE_FILE=0
014
NOT_OVERWRITE_FILE=1
015
016
create_mkdir(){
017
mkdir
$1
> /dev/null 2>&1
018
if
[
$? = 0 ];
then
019
echo
/$1
had created
020
else
021
echo
/$1
had exist
022
fi
023
024
}
025
check_file_exist(){
026
if
[
-e $1 ];
then
027
while
:;
do
028
echo
-n
"the
$1 had exist , do you want to overwrite?(y(Y) done:n(N) not:e(E) exit) : "
029
read
check_file_exist_ans
030
case
$check_file_exist_ans
in
031
y|Y)
032
echo
you
answer y
033
return
$OVERWRITE_FILE
034
;;
035
n|N)
036
echo
you
answer n
037
return
$NOT_OVERWRITE_FILE
038
;;
039
e|E)
040
exit
041
;;
042
*)
043
echo
"fuck
,i need you correct answer!"
044
esac
045
done
046
else
047
return
$OVERWRITE_FILE
048
fi
049
}
050
CREATE_NEW_FLIE=0
051
CREATE_NEW_FILE_ERROR=1
052
EXIST_FILE=2
053
INSERT_FILE_CON=
""
054
055
get_c_init_context(){
056
#$1
path/filename.ext
057
#$2
filename
058
INSERT_FILE_CON=
"/***************\n$1\n
by luckystar\n ***************/\n"
059
INSERT_FILE_CON+=
"static
int $2_flag =0;\n"
060
INSERT_FILE_CON+=
"\nvoid
$2_init(void){\n"
061
INSERT_FILE_CON+=
"\tif
($2_flag) {\n\t\t//log(\"module inited..\",X);\n\t\treturn;\n\t}\n"
062
INSERT_FILE_CON+=
"\t$2_flag
= 1;\n"
063
INSERT_FILE_CON+=
"\t//todo:module
init...\n\n}\n"
064
#up
is create module_init func
065
INSERT_FILE_CON+=
"\nvoid
$2_destory(void){\n"
066
INSERT_FILE_CON+=
"\tif
(!$2_flag) {\n\t\t//log(\"module not inited..\",X);\n\t\treturn;\n\t}\n"
067
INSERT_FILE_CON+=
"\t$2_flag
= 0;\n"
068
INSERT_FILE_CON+=
"\t//todo:module
destory...\n\n}\n"
069
#up
is create module_destory func
070
}
071
072
get_h_init_context(){
073
#$1
path/filename.ext
074
#$2
filename
075
INSERT_FILE_CON=
"#ifndef
_$2_H_\n#define _$2_H_\n"
076
INSERT_FILE_CON+=
"\n//ins_inc_file\n"
077
INSERT_FILE_CON+=
"\n//ins_typedef_def\n"
078
INSERT_FILE_CON+=
"\n//ins_def\n"
079
INSERT_FILE_CON+=
"\n//ins_func_declare\n"
080
INSERT_FILE_CON+=
"\n\n"
081
INSERT_FILE_CON+=
"#endif
//_$2_H_\n"
082
}
083
get_test_init_context(){
084
#$1
filename
085
#$2
libname
086
INSERT_FILE_CON=
"#include
\"$2.h\"\n"
087
INSERT_FILE_CON+=
"\n\n"
088
INSERT_FILE_CON+=
"int
main(int argc,char *argv[])\n"
089
INSERT_FILE_CON+=
"\t$2_init();\n"
090
INSERT_FILE_CON+=
"\t$2_destrory();\n"
091
INSERT_FILE_CON+=
"\treturn
0;\n"
092
INSERT_FILE_CON+=
"}\n"
093
}
094
insert_file_tmp(){
095
#$1
path/filename.ext
096
#$2
filename
097
#$3
ext mode
098
case
$3
in
099
$C_FILE_SUFFIX)
100
get_c_init_context
$1 $2
101
;;
102
$H_FILE_SUFFIX)
103
get_h_init_context
$1 $2
104
;;
105
$TEST_FILE_SUFFIX)
106
get_test_init_context
$4 $2
107
esac
108
sed
-i
"a\\$INSERT_FILE_CON"
$1
109
 
110
}
111
112
create_file_in_sub_dir(){
113
 
114
if
[
-d $1 ];
then
115
if
[
$3= $TEST_FILE_SUFFIX ];
then
116
NEW_FILENAME=$1/test_$4_main.c
117
else
118
NEW_FILENAME=$1/$2$3
119
fi
120
check_file_exist
$NEW_FILENAME
121
if
[
$? = $OVERWRITE_FILE ];
then
122
echo
>
$NEW_FILENAME
123
insert_file_tmp
$NEW_FILENAME $2$3$4
124
echo
create
/$MODULE_NAME/$NEW_FILENAME
file
125
return
$CREATE_NEW_FILE
126
else
127
return
$EXIST_FILE
128
fi
129
else
130
echo
/$MODULE_NAME/$1
is not directory, create_file not
continue
...
131
return
$CREATE_NEW_FILE_ERROR
132
#not
exit , continue done the other cmd
133
fi
134
}
135
136
137
check_other_cmd(){
138
while
[
2 -
le
$
#
];do
139
case
$2
in
140
$CREATE_FILE_FLAG)
141
shift
142
create_file_in_sub_dir
$SRC_DIR_NAME $2$C_FILE_SUFFIX
#$C_FILE_TMP
143
create_file_in_sub_dir
$INC_DIR_NAME $2$H_FILE_SUFFIX
#$H_FILE_TMP
144
 
145
#create_file_in_sub_dir
$LOG_DIR_NAME $2$LOG_FILE_SUFFIX
146
 
147
;;
148
$CREATE_TEST_FILE_FLAG)
149
shift
150
create_file_in_sub_dir
$SRC_DIR_NAME $2$TEST_FILE_SUFFIX $3
151
shift
152
 
153
;;
154
*)
155
#
echo $2" test "
156
esac
157
shift
158
done
159
exit
160
}
161
create_mkdir
$MODULE_NAME
162
if
[
-d $MODULE_NAME ];
then
163
cd
$MODULE_NAME
164
create_mkdir
$SRC_DIR_NAME
165
create_mkdir
$INC_DIR_NAME
166
create_mkdir
$BIN_DIR_NAME
167
create_mkdir
$OBJ_DIR_NAME
168
check_other_cmd
$@
169
else
170
echo
$MODULE_NAME
is not directory ,could not
continue
...
171
exit
172
fi
这里需要有几个声明的:

1、这个离理解configure的距离还差的很远。我尽可能的用函数调用,和简单的方式实现。当然有更精炼的操作方式。不过脚本语言一直有个悖论。高效 的看不懂,看得懂的不高效。而我本身主业是搞算法优化的,包括从系统架构上做调整。所以我对脚本的设计,追求一点:但求好看,不求高效。

估计又要被喷了,你做优化的还不要高效?我现在开始狡辩,如下:

1、优化讲究目标。而不存在没有任何边界或者没有任何约束的优化。

2、脚本的最大作用在于自动化的完成任务。但它是通过其他功能模块实现核心处理,脚本要什么都能做就不是脚本了。如果仅凭脚本自身就能做C都不能做的事情,那和汇编有什么区别,且不谈其他高级语言。

3、用脚本的,不会只RUN一次。不会是个小事情,步骤单一的操作。一定是比较复杂的,或步骤繁琐的目标组合。

4、现实中有两种脚本,一个是自己写的,一个是产品化发布中存在的。

总结一下,轮到但凡自己写的,优化目标不是脚本自身运行的高效。同时,自己写的,不是给自己看的,就是给同事看的,而且会随项目的推进而做调整,因此,脚本本身优化的目标就是在于易读易改,而不是脚本自身的速度(不谈脚本所调用的其他模块的运行效率问题 )。

我可没说我只做运行速度的优化。开发速度的优化也是优化。我自己写的代码足够快,也不可能是天下第一。我就是做了天下第一的一个软件,也不可能各个软件都 天下第一。我更希望的去优化一个团队的组织行为,而不是工作目标本身。如同,美女值得调戏,但是你能调戏尽天下所有美女吗?因此,告诉新手组织化调戏的手 段,比调戏本身更重要。

对于那些非产品级发布的脚本,写的高效的,准确说,我连用都不用,更别提看了。因为有理解你脚本的功夫,不如我自己写了。不理解清楚脚本的目标和工作原理 对我毫无价值。也希望新手保持个习惯,不要拿脚本设计来当作智力的体现,爱因斯坦成名那会也没有脚本这玩意啊。设计脚本的评价目标就是“易读,易改”。

最后,建议新手:

毕竟是linux下的C编程,基本的脚本命令和格式还是要会的。希望上述脚本作为模版,有利于你理解脚本的一些常用操作方式。同时记得ctrl+c ctrl+v保存为文件后,除了爱其什么名字就起什么名字,你得如下操作(如果你和我一样起名为create_moudule.sh)

1
$
chmod
+x
create_module.sh
为什么这么做,记得gcc main.c 输出为什么是a.out吗?我们在linux下面,不是微软的win下。

同时建议高手:

能有空对我的脚本进行改动修正,前提是更易读,更易改。

关于Makefile:

C代码可不是弱智版的(后面会展开讨论),我自动生成没关系。Makefile现在是弱智版的,我自动生成,脑袋进水了。大家和外我一样慢慢码吧。

转自http://my.oschina.net/luckystar/blog/67083
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: