UNIX下make命令、gcc命令以及makefile怎么写

0.一个程序的编译过程:

0.1 gcc(-E、-S、-o)


预处理:就是将.c转为.i,将.c中需要调用的头文件包含进来,比如会出现调用的函数的声明部分,替换#define的宏常量和宏代码段,去掉注释,预处理阶段不检查语法错误
gcc -E Demo.c-o Demo.i
编译:将.i文件中源码转化为汇编代码.s文件,编译肯定会检查语法错误
gcc -S Demo.i -o Demo.s
汇编: 将.s文件中的汇编源码转化未机器能执行的二进制机器码,生成目标文件.o
gcc -c Demo.s -o Demo.o
链接:要把函数库中的函数定义给关联进来
gcc Demo.o -o Demo

0.2 gcc生成.a文件

在Linux中,静态库的另一个名字叫归档文件(archive),管理这种归档文件的工具叫 ar
例子:
在头文件 say.h包含函数 sayHello()的原型和类 Say 的定义:

/* say.h */
#include <iostream>
extern void sayhello(void);
class Say {
    private:
        char *string;
    public:
        Say(char *str)
        {
            string = str;
        }
        void sayThis(const char *str)
        {
            std::cout << str << " from a static library\n";
        }
        void sayString(void);
};

say.cpp是要加入到静态库中的两个对象文件之一的源码。它包含 Say 类中 sayString()函数的定义体;类 Say 的一个实例 librarysay的声明也包含在内:

/* say.cpp */
#include "say.h"
void Say::sayString()
{
    std::cout << string << "\n";
}
Say librarysay("Library instance of Say");

源码文件 syshello.cpp 是我们要加入到静态库中的第二个对象文件的源码。它包含函数 sayhello() 的定义:

/* sayhello.cpp */
#include "say.h"
void sayhello()
{
    std::cout << "hello from a static library\n";
}

编译成静态库文件:

$ g++ -c sayhello.cpp
$ g++ -c say.cpp
$ ar -r libsay.a sayhello.o say.o // ar 配合参数 -r 创建一个新库 libsay.a 

主程序saymain.cpp调用该静态库

/* saymain.cpp */
#include "say.h"
int main(int argc,char *argv[])
{
    extern Say librarysay; //表明这个对象在其他模块中已经定义过了
    Say localsay = Say("Local instance of Say");
    sayhello();
    librarysay.sayThis("howdy");
    librarysay.sayString();
    localsay.sayString();
    return(0);
}

编译和链接:

$ g++ saymain.cpp libsay.a -o saymain

执行saymain,生成:

hello from a static library
howdy from a static library
Library instance of Say
Local instance of Say

1.关于makefile:

makefile文件类似一个脚本,用于执行Linux端工程文件的编译操作
make工具的三部分:
  a. 明确编译的目标
  b. 目标的依赖内容
  c. 执行怎样的操作
例子:a依赖b,执行cmdbtoa操作(注意使用tab分隔要运行的指令操作)

a:b
	cmdbtoa

2.makefile具体怎么写:

准备两个.cpp一个.h
 
text1.cpp

#include<stdio.h>
#include "test2.h"
 
int main() 
{
    printf("This is test1!\n");
    PrintTest2();
    return 0;
}

 
test2.cpp

#include<stdio.h>
#include "test2.h"

void PrintTest2() 
{
    printf("This is test2!\n");
}

 
text2.h

#ifndef TEST2_H_
#define TEST2_H_
 
void PrintTest2();

#endif

接着写一个Makefile文件:

test: test1.o test2.o //test依赖目标文件test1.o、test2.o
	gcc -Wall test1.o test2.o -o test //编译链接test1.o、test2.o,修改生成的exe文件名为test
    
test1.o: test1.c test2.h
	gcc -c -Wall test1.c -o test1.o //仅执行编译test1.c不链接,修改生成目标文件名为test1.o

test2.o: test2.c test2.h
	gcc -c -Wall test2.c -o test2.o

clean: 
    rm -rf *.o test //删除掉所有.o以及可执行文件,make clean执行

解释一下:
  
-Wall:输出所有警告信息。
-c: 只编译不链接,所以只生成目标文件.0
-o:表示指定编译后可执行文件的名称,-o后加exe文件名,不加gcc就给出预设的可执行文件a.out
-S:只激活预处理和编译,就是指把文件编译成为汇编代码。
-E: 预处理生成.i)

gcc -c hello.c 编译生成hello.o文件
gcc -o hello hello.c 生成可执行文件hello

3.makefile中使用变量($符调用):

OBJS = test1.o test2.o
G = gcc
CFLAGS = -Wall -O -g
 
test:$(OBJS)
	$(G) $(OBJS) -o test
 
test1.o:test1.c test2.h
	$(G) $(CFLAGS) -c test1.c
test2.o:test2.c test2.h
	$(G) $(CFLAGS) -c test2.c
 
clean:
	rm -rf *.o test

解释一下
变量的格式是“变量名= 内容”;若要引用这个变量,只需要用:$(变量名)
-O:在编译时进行优化。
-g:表示编译debug版本

4.makefile中使用函数:

C = gcc
G = g++
CFLAGS = -Wall -O -g
TARGET = ./test
 
%.o:%.c
	$(C) $(CFLAGS) -c $< -o $@
 
%.o:%.cpp
	$(G) $(CFLAGS) -c $< -o $@
 
SOURCES = $(wildcard *.c *.cpp)
 
OBJS = $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES)))
 
$(TARGET):$(OBJS)
	$(G) $(OBJS) -o $(TARGET)
	chmod a+x $(TARGET)
 
clean:
	rm -rf *.o test
posted @ 2022-03-29 14:31  周小鱼丶  阅读(139)  评论(0)    收藏  举报