​ — …

—include

​ —a.h

​ —b.h

​ — modele.h

​ — …

main.c

这种方法优点是易于理解,但是当开源库源代码文件较多时,直接复制过去容易和原有源代码文件杂糅在一起,不好管理。从实际上看,我们其实也不需要对开源库的源文件,我们只是想和使用C语言标准库一样调用接口就行了。

因此我们一般会将开源库编译成库文件给我们调用。


2. C语言项目编译运行的方式

在linux环境下,一般都是通过gcc和Makefile在命令行中进行编译。

在Windows下,我们也可以使用命令行来对项目进行编译,这和linux是一样的,只不过编程环境的搭建会麻烦一点。现在非常流行的vscode其实也是利用gcc来进行编译的,只不过我们把编译器路径和编译命令放进了配置文件中。在Windows下,更多的是在IDE中进行C语言项目编译,比如微软VisualStudio,DEV-C++。

下面在WIndows下分别演示一下这三种方法,首先我们来看一下这次演示的所有代码文件。

img

add.c

#include <stdio.h>
#include “add.h”

int add(int i,int j){
printf(“do add\n”);
return i+j;
}

add.h

#ifndef _ADD_H
#define _ADD_H

int add(int i,int j);

#endif

data.h

#ifndef _DATA_H
#define _DATA_H

int i=1;
int j=2;

#endif

main.c

#include <stdio.h>
#include “add.h”
#include “sub.h”
#include “data.h”

extern int i;
extern int j;

int main(){
printf(“i + j = %d\n”,add(i,j));
printf(“i - j = %d\n”,sub(i,j));
return 0;
}

sub.c

#include <stdio.h>
#include “sub.h”

int sub(int a, int b) {
printf(“do sub\n”);
return a - b;
}

sub.h

#ifndef _SUB_H
#define _SUB_H

int sub(int a, int b);

#endif

可以看出上面这些代码文件都是非常简单的,但包括了基本的依赖关系,便于我们整体把握项目,而不拘泥于细节。

1. 在vscode中用命令行进行编译(gcc和Makefile)

如果不适用Makefile的话,在源文件不是很多的时候是可行的,在本例中,编译命令为:

gcc main.c add.c sub.c -o out.exe //编译生成可执行文件
./out.exe //运行生成的可执行文件
打印结果为:
do add
i + j = 3
do sub
i - j = -1

如果源代码文件一多的话,我们一般就需要通过Makefile来管理了,Makefile的写法我就不细说了,大家可以网上找资料学习学习。

首先本例中的makefile如下:

a : main.o add.o sub.o
gcc -o a.exe main.o add.o sub.o
main.o : main.c add.h sub.h data.h
gcc -c main.c
add.o : add.c add.h data.h
gcc -c add.c
sub.o : sub.c sub.h data.h
gcc -c sub.c

在命令行中输入

make
命令行中会显示:
gcc -c main.c
gcc -c add.c
gcc -c sub.c
gcc -o a main.o add.o sub.o
在键入./a.exe
命令行中会显示如下结果,和上面是完全一样的。
do add
i + j = 3
do sub
i - j = -1

2. 在DEVC++中编译

直接新建项目

image-20210630225458895

把文件全部添加进去

image-20210630225546203

直接点击编译运行即可

image-20210630225728027

看起来IDE编译运行只需要一个按钮,实际上IDE也是帮我们默默的维护一个Makefile,在该项目目录下就存在一个Makefile文件,打开其内容如下:

Project: 项目1

Makefile created by Dev-C++ 5.11

CPP = g++.exe
CC = gcc.exe
WINDRES = windres.exe
OBJ = add.o main.o sub.o
LINKOBJ = add.o main.o sub.o
LIBS = -L"D:/Dev-Cpp/MinGW64/lib" -L"D:/Dev-Cpp/MinGW64/x86_64-w64-mingw32/lib" -static-libgcc
INCS = -I"D:/Dev-Cpp/MinGW64/include" -I"D:/Dev-Cpp/MinGW64/x86_64-w64-mingw32/include" -I"D:/Dev-Cpp/MinGW64/lib/gcc/x86_64-w64-mingw32/4.9.2/include"
CXXINCS = -I"D:/Dev-Cpp/MinGW64/include" -I"D:/Dev-Cpp/MinGW64/x86_64-w64-mingw32/include" -I"D:/Dev-Cpp/MinGW64/lib/gcc/x86_64-w64-mingw32/4.9.2/include" -I"D:/Dev-Cpp/MinGW64/lib/gcc/x86_64-w64-mingw32/4.9.2/include/c++"
BIN = 项目1.exe
CXXFLAGS = $(CXXINCS)
CFLAGS = $(INCS)
RM = rm.exe -f

.PHONY: all all-before all-after clean clean-custom

all: all-before $(BIN) all-after

clean: clean-custom
${RM} $(OBJ) $(BIN)

$(BIN): $(OBJ)
$(CPP) $(LINKOBJ) -o $(BIN) $(LIBS)

add.o: add.c
$(CPP) -c add.c -o add.o $(CXXFLAGS)

main.o: main.c
$(CPP) -c main.c -o main.o $(CXXFLAGS)

sub.o: sub.c
$(CPP) -c sub.c -o sub.o $(CXXFLAGS)

可以看出,DEVC++也是用gcc和Makefile来帮我们管理项目的。

3. 使用visual studio来编译项目

创建一个空项目

image-20210630230919379

把文件都添加进去,如下图所示

image-20210630230959895

点击调试->开始执行(不调试)

image-20210630231122063

结果如下图所示

image-20210630231230332

和前面的结果是一样的。

上面用了在Windows上常见的几种编译C语言项目的方法,可以发现用gcc和Makefile来编译项目是最灵活的,但是有一些使用门槛。而使用编译器可以更加方便快捷的来编译项目。两种方法各有优劣,大家则需选择,建议两种方法都要会用。


此外上面我们演示的是编译生成可执行文件的例子,但很多时候,我们的项目只需要编译打包成库文件提供给别人使用,因此我们要生成的就不是可执行文件,而是库文件。

那么库文件又是什么呢?

上面使用Makefile编译的时候,编译生成可执行文件其实是分成了两步。

第一步将每一个.c文件及其包含的.h文件编译生成.o文件(也叫目标文件)。

然后将所有的.o文件链接起来生成可执行文件。

将一个或多个目标文件打包起来就是库文件(目标文件的仓库)。

库文件也分为静态库和动态库,具体区别可自己查询。

4. 下面演示一下用gcc命令行来生成静态库和动态库。

在我们之前项目的基础上,假如我么要增加一个乘法功能,我们想使用一个乘法开源库。(实际上我们是可以直接用乘法的,这边知识为了演示的方便所以选择了一个简单的开源库,方便说清楚)

这个乘法开源库只有两个文件(一般开源库是不会这么简单的,这里我们是为了演示的方便)

-----mult.c

-----mult.h

文件内容为:

mult.c

#include <stdio.h>
#include “data.h”
#include “mult.h”

int mult(int a, int b) {
printf(“do mult\n”);
return a*b;
}

mult.h

#ifndef _MULT_H
#define _MULT_H

int mult(int a, int b);

#endif

下面我们要尝试将这个演示用的开源库(mult.c mult.h)编译成静态库和动态库文件。

使用gcc编译开源库成库文件同样可以使用Makefile,但因为这边源文件较少,我们就直接用gcc命令行来编译该开源库。

生成静态库:

命令行中依次输入

gcc -c mult.c //会生成mult.o文件
ar rcs libmult.a mult.o //将mult.o打包成libmult.a静态库文件

生成动态库:

命令行中依次输入

gcc -fpic -shared mult.c -o dllmult.so //生成dllmult.so动态库文件

静态库和动态库文件的使用

在编译好静态库或者动态库之后,我们只需要将库文件加头文件给需要使用这个开源库的项目就可以,那么我们之前的项目要怎么使用这个演示用的开源库呢?

静态库文件的使用

当我们把libmult.a和mult.h文件拿到之后,我们通过mult.h文件可以知道这个库向外提供的接口(函数),我们发现正好有我们需要的乘法功能,接口为int mult(int a, int b);

我们修改main.c文件成下图所示

#include <stdio.h>
#include “add.h”
#include “sub.h”
#include “data.h”
#include “mult.h”

extern int i;
extern int j;

int main(){
printf(“i + j = %d\n”,add(i,j));
printf(“i - j = %d\n”,sub(i,j));
printf(“i * j = %d\n”,mult(i,j));//增加该行
return 0;
}

要使用静态库,直接把libmult.a加入链接即可。

命令行中输入

gcc -c main.c add.c sub.c //生成main.o add.o sub.o目标文件
gcc main.o add.o sub.o libmult.a -o a.exe//将上面生成的目标文件和静态库链接起来,生成可执行文件
./a.exe //执行可执行文件,输出结果如下所示
do add
i + j = 3
do sub
i - j = -1
do mult
i * j = 2

动态库文件的使用

命令行中输入

gcc main.o add.o sub.o dllmult.so -o a.exe
./a.exe //输出结果如下所示
do add
i + j = 3
do sub
i - j = -1
do mult
i * j = 2

5. 顺便我们来用DEVC++和VisualStudio来演示一下如何生成库文件。

DEVC++生成静态库

新建项目,可以看到存在static library和DLL选项,分别对应静态库和动态库。

image-20210701002830797

将开源库文件mult.c和mult.h加入到项目中

image-20210701003315051

点击编译一下,就可以在项目目录下发现.a静态库文件啦。

image-20210701003236468

此外我们还可以看看编译静态库文件的Makefile文件是怎样的,如下图

Project: 项目3

Makefile created by Dev-C++ 5.11

CPP = g++.exe
CC = gcc.exe
WINDRES = windres.exe
OBJ = mult.o
LINKOBJ = mult.o
LIBS = -L"D:/Dev-Cpp/MinGW64/lib" -L"D:/Dev-Cpp/MinGW64/x86_64-w64-mingw32/lib" -static-libgcc
INCS = -I"D:/Dev-Cpp/MinGW64/include" -I"D:/Dev-Cpp/MinGW64/x86_64-w64-mingw32/include" -I"D:/Dev-Cpp/MinGW64/lib/gcc/x86_64-w64-mingw32/4.9.2/include"
CXXINCS = -I"D:/Dev-Cpp/MinGW64/include" -I"D:/Dev-Cpp/MinGW64/x86_64-w64-mingw32/include" -I"D:/Dev-Cpp/MinGW64/lib/gcc/x86_64-w64-mingw32/4.9.2/include" -I"D:/Dev-Cpp/MinGW64/lib/gcc/x86_64-w64-mingw32/4.9.2/include/c++"
BIN = 项目3.a
CXXFLAGS = $(CXXINCS)
CFLAGS = $(INCS)
RM = rm.exe -f

.PHONY: all all-before all-after clean clean-custom

all: all-before $(BIN) all-after

clean: clean-custom
${RM} $(OBJ) $(BIN)

$(BIN): $(LINKOBJ)
ar r $(BIN) $(LINKOBJ)
ranlib $(BIN)

mult.o: mult.c
$(CPP) -c mult.c -o mult.o $(CXXFLAGS)

DEVC++使用静态库

image-20210701004617542

image-20210701005339598

6. VisualStudio创建静态库和VisualStudio使用静态库

这方面的内容我就不直接演示了,直接分享写的比较好的博客吧。

VS2010/2013下生成并使用静态库

以OpenCV库为例讲解如何在VS中配置第三方动态库

在自己的项目中调用别人的库的方法(static lib库,dynamic lib库以及dll动态库)

C语言函数库:动态链接库与静态链接库


3. 找几个开源库来实战演练一下

优秀的C语言开源库有不少,因此这篇文章我也会一直更新,每次遇到有意思的C语言开源库的编译使用都会放在这里。


1. zlog的编译使用

项目GitHub地址:zlog

中文手册:手册

zlog在Windows上的移植:WinZlog

将zlog的源码下载下来,打开,可以看到目录结果如下图所示

image-20210701202301523

一般来说,对于一个C语言项目,最重要的就是其源码和编译规则。

对应到上面目录中的文件就是src目录和makefiel,src目录中就是源代码文件,makefile就是编译规则,我们只需要根据makefile就可以编译出我们想要的库文件。

下面是该开源库带的makefile:

zlog makefile

Copyright © 2010-2012 Hardy Simpson HardySimpson1984@gmail.com

This file is released under the LGPL 2.1 license, see the COPYING file

OBJ=
buf.o
category.o
category_table.o
conf.o
event.o
format.o
level.o
level_list.o
mdc.o
record.o
record_table.o
rotater.o
rule.o
spec.o
thread.o
zc_arraylist.o
zc_hashtable.o
zc_profile.o
zc_util.o
zlog.o
BINS=zlog-chk-conf
LIBNAME=libzlog

ZLOG_MAJOR=1
ZLOG_MINOR=2

Fallback to gcc when $CC is not in $PATH.

CC:=$(shell sh -c 'type $(CC) >/dev/null 2>/dev/null && echo ( C C ) ∣ ∣ e c h o g c c ′ ) O P T I M I Z A T I O N ? = − O 2 W A R N I N G S = − W a l l − W s t r i c t − p r o t o t y p e s − f w r a p v D E B U G ? = − g − g g d b R E A L C F L A G S = (CC) || echo gcc') OPTIMIZATION?=-O2 WARNINGS=-Wall -Wstrict-prototypes -fwrapv DEBUG?= -g -ggdb REAL_CFLAGS= (CC)∣∣echogcc)OPTIMIZATION?=O2WARNINGS=WallWstrictprototypesfwrapvDEBUG?=gggdbREALCFLAGS=(OPTIMIZATION) -fPIC -pthread $(CFLAGS) $(WARNINGS) ( D E B U G ) R E A L L D F L A G S = (DEBUG) REAL_LDFLAGS= (DEBUG)REALLDFLAGS=(LDFLAGS) -pthread

DYLIBSUFFIX=so
STLIBSUFFIX=a
DYLIB_MINOR_NAME= ( L I B N A M E ) . (LIBNAME). (LIBNAME).(DYLIBSUFFIX). ( Z L O G M A J O R ) . (ZLOG_MAJOR). (ZLOGMAJOR).(ZLOG_MINOR)
DYLIB_MAJOR_NAME= ( L I B N A M E ) . (LIBNAME). (LIBNAME).(DYLIBSUFFIX). ( Z L O G M A J O R ) D Y L I B N A M E = (ZLOG_MAJOR) DYLIBNAME= (ZLOGMAJOR)DYLIBNAME=(LIBNAME). ( D Y L I B S U F F I X ) D Y L I B M A K E C M D = (DYLIBSUFFIX) DYLIB_MAKE_CMD= (DYLIBSUFFIX)DYLIBMAKECMD=(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) ( L D F L A G S ) S T L I B N A M E = (LDFLAGS) STLIBNAME= (LDFLAGS)STLIBNAME=(LIBNAME).$(STLIBSUFFIX)
STLIB_MAKE_CMD=ar rcs $(STLIBNAME)

Installation related variables

PREFIX?=/usr/local
INCLUDE_PATH=include
LIBRARY_PATH=lib
BINARY_PATH=bin
INSTALL_INCLUDE_PATH= ( P R E F I X ) / (PREFIX)/ (PREFIX)/(INCLUDE_PATH)
INSTALL_LIBRARY_PATH= ( P R E F I X ) / (PREFIX)/ (PREFIX)/(LIBRARY_PATH)
INSTALL_BINARY_PATH= ( P R E F I X ) / (PREFIX)/ (PREFIX)/(BINARY_PATH)

Platform-specific overrides

uname_S := $(shell sh -c ‘uname -s 2>/dev/null || echo not’)

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Go语言工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Go语言全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Golang知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Go)
img

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

因此收集整理了一份《2024年Go语言全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-Z5V60Yrb-1712959628521)]
[外链图片转存中…(img-NtFuRVda-1712959628522)]
[外链图片转存中…(img-SUyvZD4N-1712959628523)]
[外链图片转存中…(img-61lDFXss-1712959628523)]
[外链图片转存中…(img-k2Gafh9y-1712959628524)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Golang知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-nV6s4Ezi-1712959628524)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐