Linux Makefile编写之静态库

11 篇文章 0 订阅
4 篇文章 0 订阅

1 概述

  编译工具有很多(make/cmake/BJam)。如果不考虑跨平台的话,还是make比较方便。使用make编译需要编写Makefile。本文编写Makefile来生成C/C++静态库。

2 Makefile文件命名

Makefile文件首先是一个文本文件,Linux下默认有两种命名方式:

  • Makefile 这是最常用的命名方式
  • makefile 这是优先级高的命名方式

在工程目录下运行make命令,make程序先找makefile,如果没有makefile再找Makefile文件。也就是说如果makefile和Makefile两个文件都存在默认使用makefile。

其实Makefile的文件名可以是任意的,例如Buildfile,可以使用下面命令编译:

make -f BuildFile

本文使用make程序版本:

$make --version
GNU Make 4.2.1
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

3 MakeFile实例

这里以CppTest库代码为例,代码目录结构:

cpptest$ tree
.
├── Makefile
├── inc
│   ├── cpptest-assert.h
│   ├── cpptest-collectoroutput.h
│   ├── cpptest-compileroutput.h
│   ├── cpptest-htmloutput.h
│   ├── cpptest-output.h
│   ├── cpptest-source.h
│   ├── cpptest-suite.h
│   ├── cpptest-textoutput.h
│   ├── cpptest-time.h
│   └── cpptest.h
└── src
    ├── collectoroutput.cpp
    ├── compileroutput.cpp
    ├── config.h
    ├── htmloutput.cpp
    ├── missing.cpp
    ├── missing.h
    ├── source.cpp
    ├── suite.cpp
    ├── textoutput.cpp
    ├── time.cpp
    ├── utils.cpp
    ├── utils.h
    └── winconfig.h

2 directories, 24 files

Makefile文件如下:

PROJECT_NAME ?= cpptest

CC ?= gcc
CXX ?= g++
AR  ?= ar

CFLAGS := 
C++FLAGS := -std=c++11
LIBFLAGS := -rcD

PWD := $(shell pwd)
INCS :=  -I$(PWD)/inc
SRCDIR := $(PWD)/src
LIBDIR := $(PWD)/lib
LIBNAME := $(LIBDIR)/lib$(PROJECT_NAME).a

CSRC := $(wildcard $(SRCDIR)/*.c)
OBJS := $(patsubst %.c,%.o,$(CSRC))

CPPS := $(wildcard $(SRCDIR)/*.cpp)
CPPOBJS := $(patsubst %.cpp,%.o,$(CPPS))

all: $(OBJS) $(CPPOBJS) $(LIBDIR)
	$(AR) $(LIBFLAGS) $(LIBNAME) $(OBJS) $(CPPOBJS)  

$(OBJS): %.o:%.c
	$(CC) -c $(CFLAGS) $(INCS) $< -o $@

$(CPPOBJS): %.o:%.cpp
	$(CXX)  -c $(C++FLAGS) $(INCS) $< -o $@

$(LIBDIR):
	@mkdir $(LIBDIR) -p

.PHNOY:clean
clean:
	@rm -f $(OBJS) $(CPPOBJS)
	@rm -f $(LIBNAME)

编译结果:

cpptest$ make
g++  -c -std=c++11 -I/home/james/git/cpptest/inc /home/james/git/cpptest/src/utils.cpp -o /home/james/git/cpptest/src/utils.o
g++  -c -std=c++11 -I/home/james/git/cpptest/inc /home/james/git/cpptest/src/source.cpp -o /home/james/git/cpptest/src/source.o
g++  -c -std=c++11 -I/home/james/git/cpptest/inc /home/james/git/cpptest/src/time.cpp -o /home/james/git/cpptest/src/time.o
g++  -c -std=c++11 -I/home/james/git/cpptest/inc /home/james/git/cpptest/src/collectoroutput.cpp -o /home/james/git/cpptest/src/collectoroutput.o
g++  -c -std=c++11 -I/home/james/git/cpptest/inc /home/james/git/cpptest/src/textoutput.cpp -o /home/james/git/cpptest/src/textoutput.o
g++  -c -std=c++11 -I/home/james/git/cpptest/inc /home/james/git/cpptest/src/compileroutput.cpp -o /home/james/git/cpptest/src/compileroutput.o
g++  -c -std=c++11 -I/home/james/git/cpptest/inc /home/james/git/cpptest/src/htmloutput.cpp -o /home/james/git/cpptest/src/htmloutput.o
g++  -c -std=c++11 -I/home/james/git/cpptest/inc /home/james/git/cpptest/src/suite.cpp -o /home/james/git/cpptest/src/suite.o
g++  -c -std=c++11 -I/home/james/git/cpptest/inc /home/james/git/cpptest/src/missing.cpp -o /home/james/git/cpptest/src/missing.o
ar -rcD /home/james/git/cpptest/lib/libcpptest.a  /home/james/git/cpptest/src/utils.o /home/james/git/cpptest/src/source.o /home/james/git/cpptest/src/time.o /home/james/git/cpptest/src/collectoroutput.o /home/james/git/cpptest/src/textoutput.o /home/james/git/cpptest/src/compileroutput.o /home/james/git/cpptest/src/htmloutput.o /home/james/git/cpptest/src/suite.o /home/james/git/cpptest/src/missing.o

说明:

  • 编译生成静态库libcpptes.a文件放在lib目录下
  • 编译生成.o与源码在同一目录

4 代码分析

4.1 定义变量

PROJECT_NAME ?= cpptest

CC ?= gcc
CXX ?= g++
AR  ?= ar

说明:

  • 定义工程名,C/C++编译器名称和生成库程序名称。
  • ?=格式定义变量可以通过环境变量修改,例如工程名修改为CppTest需要在命令上执行命令: export PROJECT_NAME=CppTest
  • 编译器名称也可以修改,例如:export CC=arm-xilinx-linux-gnueabi-gcc,这样就可交叉编译了。

4.2 定义编译选项

CFLAGS := 
C++FLAGS := -std=c++11
LIBFLAGS := -rcD

说明:

  • 定义C/C++编译选项,C++使用C++11标准。
  • 定义生成库选项

4.3 定义路径

PWD := $(shell pwd)
INCS :=  -I$(PWD)/inc
SRCDIR := $(PWD)/src
LIBDIR := $(PWD)/lib
LIBNAME := $(LIBDIR)/lib$(PROJECT_NAME).a

说明:

  • 调用shell命令pwd获取当前路径PWD
  • 利用PWD定义include/src/lib路径
  • 定义生成库名称
  • 注意这里定义变量是通过:=来定义的,这种变量没法通过环境变量修改。

4.4 自动选择译源文件

CSRC := $(wildcard $(SRCDIR)/*.c)
OBJS := $(patsubst %.c,%.o,$(CSRC))

CPPS := $(wildcard $(SRCDIR)/*.cpp)
CPPOBJS := $(patsubst %.cpp,%.o,$(CPPS))

说明:

  • 调用函数wildcard扫描src下所有.c/.cpp文件
  • 调用函数patsubst通过源文件生成.o目标文件

4.5 编译依赖项

all: $(OBJS) $(CPPOBJS) $(LIBDIR)
	$(AR) $(LIBFLAGS) $(LIBNAME) $(OBJS) $(CPPOBJS)  

$(OBJS): %.o:%.c
	$(CC) -c $(CFLAGS) $(INCS) $< -o $@

$(CPPOBJS): %.o:%.cpp
	$(CXX)  -c $(C++FLAGS) $(INCS) $< -o $@

$(LIBDIR):
	@mkdir $(LIBDIR) -p

.PHNOY:clean
clean:
	@rm -f $(OBJS) $(CPPOBJS)
	@rm -f $(LIBNAME)

说明:

  • $(OBJS)依赖项编译.c文件为.o文件
  • $(CPPOBJS)依赖项编译.cpp文件为.o文件
  • $(LIBDIR)依赖项创建目录lib
  • all依赖项将.o文件生成lib文件。
  • clean依赖项删除编译生成.o和.a文件。
  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flysnow010

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值