概述:
通过Makefile传递宏参数进行挑拣编译,是编程中常用的技术。
Windows我不会,也不想会。这里只谈 Linux/GNU系统。
在Linux平台下,编程大体分为两种,内核态编程和用户空间编程。对于内核态编程,对于大多数人而言,
都是采用内核模块的方式,将自己的代码加入到内核之中。用户空间的编程就多种多样了。
但是无论是在那种context下编程,我们使用的基本上都是GNU的工具:Make,Gcc,LD等。而且无论代码要在那种context运行,都需要
经过预处理,编译,连接,代码优化等过程。在这个过程之中,这里讨论的只适用于预处理阶段,也就是说选择性的进行编译。
由于在内核态,通过kernel module的方式进行编译的时候,程序员主要是借助于Linux kernel KBuild编译系统;然而,在用户空间编程的时候,所有的工作都需要我们自己来作,所以两者之间存在不同。
一. 用户空间
因为实际上进行预处理的只是Gcc工具,而make工具只是一个解决依赖关系的工具。所以问题就简化成如何通过make向gcc传递参数。
通过简单的例子来说明:
hello.c
#include <stdio.h>
void main(void) {
#ifdef DEBUG
printf("you ask for debug!\n");
#endif
printf("we must say goodbye\n");
return;
}
Makefile:
ifeq ($(DEBUG),y)
CFLAGS := $(CFLAGS) -DDEBUG
endif
hello: hello.c
$(CC) $(CFLAGS) $< -o $@
执行过程:
[ville@localhost test]$ ls
hello.c Makefile
[ville@localhost test]$ make
cc hello.c -o hello
[ville@localhost test]$ ./hello
we must say goodbye
[ville@localhost test]$ rm hello
[ville@localhost test]$ ls
hello.c Makefile
[ville@localhost test]$ make DEBUG:=y
cc -DDEBUG hello.c -o hello
[ville@localhost test]$ ./hello
you ask for debug!
we must say goodbye
[ville@localhost test]$
通过以上的简单例子说明如何通过宏开关进行条件编译。
二. 在内核空间的module形式
KBuild是Linux Kernel的编译系统,但是最终实际执行编译连接的还是GNU GCC
LD。虽然我们是程序员,但是在KBuild的问题上,我们已经成为了软件的使用者。对于用户而言,我们应当更多关注功能,会使用是最终目的,当然如果有
时间学习一下KBuild也是十分有意义的!
有问题,看文档!Linux Kernel一向以文档不全不规范而闻名世界,但是这个KBuild的文档还是有的,
linuxXXXXX/Documentation/kbuild 目录下:
00-INDEX
kbuild.txt
kconfig-language.txt
kconfig.txt
makefiles.txt
modules.txt
有空还是要看看的!!!
在makefile.txt 第284行,---3.7 Complilation Flags一节中有说明。
以前都是使用EXTRA_XFLAGS,现在还是支持,但是建议使用xxflags-y这些内置变量了。
ccflags-y:$(CC)的编译选项添加这里,宏开关也在这里添加
asflags-y:as汇编器使用的
ldflags-y :ld链接器使用的
还是用一个例子来演示:
ville.c :
/**
* Author : ville lee
* Create Time : 2010/07/31
* Description : This module implements a virtual file system.
* Aimming at learning the theory of Linux VFS.
*
* Change Log :
* version author Date Log
*
*
*
* */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
/**
* init function of the module
*
* */
static int __init
ville_init(void)
{
#ifdef DEBUG
/* we give the debug message like: module name : function name : debug message */
printk(KERN_ALERT "ville :ville_init: you ask for debug!\n");
#endif
printk(KERN_ALERT "ville :ville_init: ville module init!\n");
return 0;
}
static void __exit
ville_exit(void)
{
#ifdef DEBUG
/* we give the debug message like: module name : function name : debug message */
printk(KERN_ALERT "ville :ville_exit: you ask for debug!\n");
#endif
printk(KERN_ALERT "ville :ville_exit: ville module exit!\n");
return;
}
module_init(ville_init);
module_exit(ville_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ville lee");
Makefile:
## if module is built in the kernel module
## system. Give the work to kbuild.
# provide the default value to module name and ccflags-y
ifeq ($(MODULE),)
MODULE := ville
endif
ifeq ($(DEBUG),y)
ccflags-y += -DDEBUG
endif
ifneq ($(KERNELRELEASE),)
obj-m := $(MODULE).o
else
KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
.PHONY:clean
clean:
echo "cleaning ...."
rm modules.order Module.symvers \
$(MODULE).ko $(MODULE).mod.c \
$(MODULE).mod.o $(MODULE).o
echo "clean up"
操作:
[ville@localhost source]$ ls
Makefile ville.c ville.h
[ville@localhost source]$ make
make -C /lib/modules/2.6.35.13-91.fc14.i686.PAE/build M=/home/ville/Programming/VFS/villefs/source modules
make[1]: Entering directory `/usr/src/kernels/2.6.35.13-91.fc14.i686.PAE'
CC [M] /home/ville/Programming/VFS/villefs/source/ville.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/ville/Programming/VFS/villefs/source/ville.mod.o
LD [M] /home/ville/Programming/VFS/villefs/source/ville.ko
make[1]: Leaving directory `/usr/src/kernels/2.6.35.13-91.fc14.i686.PAE'
[ville@localhost source]$ su
Password:
[root@localhost source]# insmod ville.ko
[root@localhost source]# tail /var/log/messages
Aug 1 21:52:20 localhost kernel: [ 527.943854] ville :ville_init: ville module init!
[root@localhost source]# rmmod ville
[root@localhost source]# tail /var/log/messages
Aug 1 21:52:20 localhost kernel: [ 527.943854] ville :ville_init: ville module init!
Aug 1 21:55:06 localhost kernel: [ 694.160046] ville :ville_exit: ville module exit!
[root@localhost source]# exit
exit
[ville@localhost source]$ ls
Makefile modules.order Module.symvers ville.c ville.h ville.ko ville.mod.c ville.mod.o ville.o
[ville@localhost source]$ make clean
echo "cleaning ...."
cleaning ....
rm modules.order Module.symvers \
ville.ko ville.mod.c \
ville.mod.o ville.o
echo "clean up"
clean up
[ville@localhost source]$ make DEBUG:=y
make -C /lib/modules/2.6.35.13-91.fc14.i686.PAE/build M=/home/ville/Programming/VFS/villefs/source modules
make[1]: Entering directory `/usr/src/kernels/2.6.35.13-91.fc14.i686.PAE'
CC [M] /home/ville/Programming/VFS/villefs/source/ville.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/ville/Programming/VFS/villefs/source/ville.mod.o
LD [M] /home/ville/Programming/VFS/villefs/source/ville.ko
make[1]: Leaving directory `/usr/src/kernels/2.6.35.13-91.fc14.i686.PAE'
[ville@localhost source]$ ls
Makefile modules.order Module.symvers ville.c ville.h ville.ko ville.mod.c ville.mod.o ville.o
[ville@localhost source]$ su
Password:
[root@localhost source]# insmod ville.ko
[root@localhost source]# tail /var/log/messages
Aug
1 21:44:24 localhost rtkit-daemon[1721]: Successfully made thread 1838
of process 1836 (/usr/bin/pulseaudio) owned by '500' RT at priority 5.
Aug
1 21:44:24 localhost rtkit-daemon[1721]: Successfully made thread 1839
of process 1836 (/usr/bin/pulseaudio) owned by '500' RT at priority 5.
Aug
1 21:44:24 localhost pulseaudio[1836]: bluetooth-util.c: Error from
ListAdapters reply: org.freedesktop.DBus.Error.Spawn.ChildExited
Aug 1
21:44:26 localhost rtkit-daemon[1721]: Successfully made thread 1870 of
process 1870 (/usr/bin/pulseaudio) owned by '500' high priority at nice
level -11.
Aug 1 21:44:26 localhost pulseaudio[1870]: pid.c: Daemon already running.
Aug
1 21:44:41 localhost dbus: [system] Rejected send message, 2 matched
rules; type="method_call", sender=":1.56" (uid=500 pid=1855
comm="nautilus) interface="org.freedesktop.DBus.Properties"
member="GetAll" error name="(unset)" requested_reply=0
destination=":1.18" (uid=0 pid=1588 comm="/usr/sbin/console-kit-daemon))
Aug 1 21:52:20 localhost kernel: [ 527.943854] ville :ville_init: ville module init!
Aug 1 21:55:06 localhost kernel: [ 694.160046] ville :ville_exit: ville module exit!
Aug 1 21:56:17 localhost kernel: [ 764.867120] ville :ville_init: you ask for debug!
Aug 1 21:56:17 localhost kernel: [ 764.867127] ville :ville_init: ville module init!
[root@localhost source]# rmmod ville
[root@localhost source]# tail /var/log/messages
Aug
1 21:44:24 localhost pulseaudio[1836]: bluetooth-util.c: Error from
ListAdapters reply: org.freedesktop.DBus.Error.Spawn.ChildExited
Aug 1
21:44:26 localhost rtkit-daemon[1721]: Successfully made thread 1870 of
process 1870 (/usr/bin/pulseaudio) owned by '500' high priority at nice
level -11.
Aug 1 21:44:26 localhost pulseaudio[1870]: pid.c: Daemon already running.
Aug
1 21:44:41 localhost dbus: [system] Rejected send message, 2 matched
rules; type="method_call", sender=":1.56" (uid=500 pid=1855
comm="nautilus) interface="org.freedesktop.DBus.Properties"
member="GetAll" error name="(unset)" requested_reply=0
destination=":1.18" (uid=0 pid=1588 comm="/usr/sbin/console-kit-daemon))
Aug 1 21:52:20 localhost kernel: [ 527.943854] ville :ville_init: ville module init!
Aug 1 21:55:06 localhost kernel: [ 694.160046] ville :ville_exit: ville module exit!
Aug 1 21:56:17 localhost kernel: [ 764.867120] ville :ville_init: you ask for debug!
Aug 1 21:56:17 localhost kernel: [ 764.867127] ville :ville_init: ville module init!
Aug 1 21:56:44 localhost kernel: [ 792.003641] ville :ville_exit: you ask for debug!
Aug 1 21:56:44 localhost kernel: [ 792.003648] ville :ville_exit: ville module exit!
总结:
通过这两个例子,就了解了如何在用户空间和内核态模块中使用开关宏来进行条件编译。
ville
文章出处:飞诺网(www.):http://www./course/6_system/linux/Linuxjs/20110802/557787.html