之前我写过一篇类似的博文,但是当时对这个内容理解还不是很透彻,因此写的很随意,也不成体系。
这次因为对一个开源库很感兴趣,所以想借着这个机会,实战演练一下怎么使用网上的开源库。
对于C语言项目开发来说,我们可以将其分类成以下几种情况:
这种情况在项目中是很少的,常见于我们刷leetcode时,或者验证算法的时候。此时源文件只有一个,且不依赖其他库(C语言标准库除外)。
这个其实和后面要说的(多文件开发,调用开源库)其实是类似的,后面我们再细说。
一般其目录结构如下:
—src
—a.c
—b.c
— …
—include
—a.h
—b.h
— …
–main.c
在这种情况下,我们一般会采取模块化的开发方式,一般一个模块包括一个.c文件和.h文件,当然也可能一个模块由几个.c文件组成,但一般一个模块只有一个.h文件,.h文件其实就是该模块向外提供的接口;也有的模块只有.h,定义一些数据变量给其他模块使用。
没有调用开源库,整个源代码只是调用了标准库或者自身模块提供的接口,因此在编译上也没有太多需要主要的点。
这种情况应该是在实际的项目中最常见的。当我们要实现某个功能时,发现已经有优秀的开源库可以实现这个功能,这时就没必要重复造轮子,直接调用该开源库即可。
一般其目录结构如下:
—src
—a.c
—b.c
— …
—include
—a.h
—b.h
— …
main.c
除了这些自身的源文件以外,我们还需要调用开源库。
在此说一下开源库的存在形式。
开源库是有源代码的,我们如果要使用该开源库,可以开源库作为一个模块,把源代码文件复制到我们的项目中,假设开源库包括module.c和module.h,复制过去之后,文件目录变成如下:
—src
—a.c
—b.c
— module.c
— …
—include
—a.h
—b.h
— modele.h
— …
main.c
这种方法优点是易于理解,但是当开源库源代码文件较多时,直接复制过去容易和原有源代码文件杂糅在一起,不好管理。从实际上看,我们其实也不需要对开源库的源文件,我们只是想和使用C语言标准库一样调用接口就行了。
因此我们一般会将开源库编译成库文件给我们调用。
在linux环境下,一般都是通过gcc和Makefile在命令行中进行编译。
在Windows下,我们也可以使用命令行来对项目进行编译,这和linux是一样的,只不过编程环境的搭建会麻烦一点。现在非常流行的vscode其实也是利用gcc来进行编译的,只不过我们把编译器路径和编译命令放进了配置文件中。在Windows下,更多的是在IDE中进行C语言项目编译,比如微软VisualStudio,DEV-C++。
下面在WIndows下分别演示一下这三种方法,首先我们来看一下这次演示的所有代码文件。
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
可以看出上面这些代码文件都是非常简单的,但包括了基本的依赖关系,便于我们整体把握项目,而不拘泥于细节。
如果不适用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
直接新建项目
把文件全部添加进去
直接点击编译运行即可
看起来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来帮我们管理项目的。
创建一个空项目
把文件都添加进去,如下图所示
点击调试->开始执行(不调试)
结果如下图所示
和前面的结果是一样的。
上面用了在Windows上常见的几种编译C语言项目的方法,可以发现用gcc和Makefile来编译项目是最灵活的,但是有一些使用门槛。而使用编译器可以更加方便快捷的来编译项目。两种方法各有优劣,大家则需选择,建议两种方法都要会用。
此外上面我们演示的是编译生成可执行文件的例子,但很多时候,我们的项目只需要编译打包成库文件提供给别人使用,因此我们要生成的就不是可执行文件,而是库文件。
那么库文件又是什么呢?
上面使用Makefile编译的时候,编译生成可执行文件其实是分成了两步。
第一步将每一个.c文件及其包含的.h文件编译生成.o文件(也叫目标文件)。
然后将所有的.o文件链接起来生成可执行文件。
将一个或多个目标文件打包起来就是库文件(目标文件的仓库)。
库文件也分为静态库和动态库,具体区别可自己查询。
在我们之前项目的基础上,假如我么要增加一个乘法功能,我们想使用一个乘法开源库。(实际上我们是可以直接用乘法的,这边知识为了演示的方便所以选择了一个简单的开源库,方便说清楚)
这个乘法开源库只有两个文件(一般开源库是不会这么简单的,这里我们是为了演示的方便)
-----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
DEVC++生成静态库
新建项目,可以看到存在static library和DLL选项,分别对应静态库和动态库。
将开源库文件mult.c和mult.h加入到项目中
点击编译一下,就可以在项目目录下发现.a静态库文件啦。
此外我们还可以看看编译静态库文件的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++使用静态库
这方面的内容我就不直接演示了,直接分享写的比较好的博客吧。
VS2010/2013下生成并使用静态库
以OpenCV库为例讲解如何在VS中配置第三方动态库
在自己的项目中调用别人的库的方法(static lib库,dynamic lib库以及dll动态库)
C语言函数库:动态链接库与静态链接库
优秀的C语言开源库有不少,因此这篇文章我也会一直更新,每次遇到有意思的C语言开源库的编译使用都会放在这里。
项目GitHub地址:zlog
中文手册:手册
zlog在Windows上的移植:WinZlog
将zlog的源码下载下来,打开,可以看到目录结果如下图所示
一般来说,对于一个C语言项目,最重要的就是其源码和编译规则。
对应到上面目录中的文件就是src目录和makefiel,src目录中就是源代码文件,makefile就是编译规则,我们只需要根据makefile就可以编译出我们想要的库文件。
下面是该开源库带的makefile:
# zlog makefile # Copyright (C) 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 $(CC) || echo gcc') OPTIMIZATION?=-O2 WARNINGS=-Wall -Wstrict-prototypes -fwrapv DEBUG?= -g -ggdb REAL_CFLAGS=$(OPTIMIZATION) -fPIC -pthread $(CFLAGS) $(WARNINGS) $(DEBUG) REAL_LDFLAGS=$(LDFLAGS) -pthread DYLIBSUFFIX=so STLIBSUFFIX=a DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(ZLOG_MAJOR).$(ZLOG_MINOR) DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(ZLOG_MAJOR) DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX) DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(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= $(PREFIX)/$(INCLUDE_PATH) INSTALL_LIBRARY_PATH= $(PREFIX)/$(LIBRARY_PATH) INSTALL_BINARY_PATH= $(PREFIX)/$(BINARY_PATH) # Platform-specific overrides uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') compiler_platform := $(shell sh -c '$(CC) --version|grep -i apple') ifeq ($(uname_S),SunOS) # REAL_LDFLAGS+= -ldl -lnsl -lsocket DYLIB_MAKE_CMD=$(CC) -G -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS) INSTALL= cp -r endif # For Darwin builds, check the compiler platform above is not empty. The covers cross compilation on Linux ifneq ($(compiler_platform),) DYLIBSUFFIX=dylib DYLIB_MINOR_NAME=$(LIBNAME).$(ZLOG_MAJOR).$(ZLOG_MINOR).$(DYLIBSUFFIX) DYLIB_MAJOR_NAME=$(LIBNAME).$(ZLOG_MAJOR).$(DYLIBSUFFIX) DYLIB_MAKE_CMD=$(CC) -dynamiclib -install_name $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) REAL_CFLAGS+= -D_DARWIN_C_SOURCE endif ifeq ($(uname_S),AIX) # this logic of minor major is not relevant on AIX or at least not widely used # not to mention dynamic linker .a preference... DYLIB_MAKE_CMD=$(CC) -shared -Wl,-G,-b64 -maix64 -pthread -o $(DYLIBNAME) $(LDFLAGS) REAL_CFLAGS+= -maix64 STLIB_MAKE_CMD=OBJECT_MODE=64 ar rcs $(STLIBNAME) $(DYLIB_MAJOR_NAME) endif all: $(DYLIBNAME) $(BINS) # Deps (use make dep to generate this) buf.o: buf.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ zc_xplatform.h zc_util.h buf.h category.o: category.c fmacros.h category.h zc_defs.h zc_profile.h \ zc_arraylist.h zc_hashtable.h zc_xplatform.h zc_util.h thread.h event.h \ buf.h mdc.h rule.h format.h rotater.h record.h category_table.o: category_table.c zc_defs.h zc_profile.h zc_arraylist.h \ zc_hashtable.h zc_xplatform.h zc_util.h category_table.h category.h \ thread.h event.h buf.h mdc.h conf.o: conf.c fmacros.h conf.h zc_defs.h zc_profile.h zc_arraylist.h \ zc_hashtable.h zc_xplatform.h zc_util.h format.h thread.h event.h buf.h \ mdc.h rotater.h rule.h record.h level_list.h level.h event.o: event.c fmacros.h zc_defs.h zc_profile.h zc_arraylist.h \ zc_hashtable.h zc_xplatform.h zc_util.h event.h format.o: format.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ zc_xplatform.h zc_util.h thread.h event.h buf.h mdc.h spec.h format.h level.o: level.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ zc_xplatform.h zc_util.h level.h level_list.o: level_list.c zc_defs.h zc_profile.h zc_arraylist.h \ zc_hashtable.h zc_xplatform.h zc_util.h level.h level_list.h mdc.o: mdc.c mdc.h zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ zc_xplatform.h zc_util.h record.o: record.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ zc_xplatform.h zc_util.h record.h record_table.o: record_table.c zc_defs.h zc_profile.h zc_arraylist.h \ zc_hashtable.h zc_xplatform.h zc_util.h record_table.h record.h rotater.o: rotater.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ zc_xplatform.h zc_util.h rotater.h rule.o: rule.c fmacros.h rule.h zc_defs.h zc_profile.h zc_arraylist.h \ zc_hashtable.h zc_xplatform.h zc_util.h format.h thread.h event.h buf.h \ mdc.h rotater.h record.h level_list.h level.h spec.h spec.o: spec.c fmacros.h spec.h event.h zc_defs.h zc_profile.h \ zc_arraylist.h zc_hashtable.h zc_xplatform.h zc_util.h buf.h thread.h \ mdc.h level_list.h level.h thread.o: thread.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ zc_xplatform.h zc_util.h event.h buf.h thread.h mdc.h zc_arraylist.o: zc_arraylist.c zc_defs.h zc_profile.h zc_arraylist.h \ zc_hashtable.h zc_xplatform.h zc_util.h zc_hashtable.o: zc_hashtable.c zc_defs.h zc_profile.h zc_arraylist.h \ zc_hashtable.h zc_xplatform.h zc_util.h zc_profile.o: zc_profile.c fmacros.h zc_profile.h zc_xplatform.h zc_util.o: zc_util.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ zc_xplatform.h zc_util.h zlog-chk-conf.o: zlog-chk-conf.c fmacros.h zlog.h zlog.o: zlog.c fmacros.h conf.h zc_defs.h zc_profile.h zc_arraylist.h \ zc_hashtable.h zc_xplatform.h zc_util.h format.h thread.h event.h buf.h \ mdc.h rotater.h category_table.h category.h record_table.h \ record.h rule.h $(DYLIBNAME): $(OBJ) $(DYLIB_MAKE_CMD) $(OBJ) $(REAL_LDFLAGS) # for use in test folder - linux and requirement for aix runtime # resolving cp -f $(DYLIBNAME) $(DYLIB_MAJOR_NAME) cp -f $(DYLIBNAME) $(DYLIB_MINOR_NAME) $(STLIBNAME): $(OBJ) $(STLIB_MAKE_CMD) $(OBJ) dynamic: $(DYLIBNAME) static: $(STLIBNAME) # Binaries: zlog-chk-conf: zlog-chk-conf.o $(STLIBNAME) $(DYLIBNAME) $(CC) -o $@ zlog-chk-conf.o -L. -lzlog $(REAL_LDFLAGS) .c.o: $(CC) -std=c99 -pedantic -c $(REAL_CFLAGS) $< clean: rm -rf $(DYLIBNAME) $(STLIBNAME) $(BINS) *.o *.gcda *.gcno *.gcov $(DYLIB_MINOR_NAME) $(DYLIB_MAJOR_NAME) dep: $(CC) -MM *.c # Installation target ifeq ($(uname_S),SunOS) INSTALL?= cp -r endif ifeq ($(uname_S),AIX) INSTALL?= cp -r endif INSTALL?= cp -a install: $(DYLIBNAME) $(STLIBNAME) mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH) $(INSTALL_BINARY_PATH) $(INSTALL) zlog.h $(INSTALL_INCLUDE_PATH) $(INSTALL) zlog-chk-conf $(INSTALL_BINARY_PATH) $(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME) cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIB_MAJOR_NAME) cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MAJOR_NAME) $(DYLIBNAME) $(INSTALL) $(STLIBNAME) $(INSTALL_LIBRARY_PATH) 32bit: @echo "" @echo "WARNING: if this fails under Linux you probably need to install libc6-dev-i386" @echo "" $(MAKE) CFLAGS="-m32" LDFLAGS="-m32" gprof: $(MAKE) CFLAGS="-pg" LDFLAGS="-pg" gcov: $(MAKE) CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="-fprofile-arcs" coverage: gcov make check mkdir -p tmp/lcov lcov -d . -c -o tmp/lcov/hiredis.info genhtml --legend -o tmp/lcov/report tmp/lcov/hiredis.info noopt: $(MAKE) OPTIMIZATION="" .PHONY: all clean dep install 32bit gprof gcov noopt
可以看出,这个makefile比我们之前写的要复杂很多,而且用到了很多linux上的命令,因此在Windows下直接编译是会报错的。如下图所示
PS E:\wenjian\cs\code\zlog\zlog\src> make process_begin: CreateProcess(NULL, sh -c "type cc >/dev/null 2>/dev/null && echo cc || echo gcc", ...) failed. process_begin: CreateProcess(NULL, sh -c "uname -s 2>/dev/null || echo not", ...) failed. process_begin: CreateProcess(NULL, sh -c " --version|grep -i apple", ...) failed. std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb buf.c 'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'buf.o' failed make: [buf.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb category.c 'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'category.o' failed make: [category.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb category_table.c 'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'category_table.o' failed make: [category_table.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb conf.c 'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'conf.o' failed make: [conf.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb event.c 'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'event.o' failed make: [event.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb format.c'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'format.o' failed make: [format.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb level.c 'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'level.o' failed make: [level.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb level_list.c 'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'level_list.o' failed make: [level_list.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb mdc.c 'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'mdc.o' failed make: [mdc.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb record.c'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'record.o' failed make: [record.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb record_table.c 'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'record_table.o' failed make: [record_table.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb rotater.c 'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'rotater.o' failed make: [rotater.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb rule.c 'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'rule.o' failed make: [rule.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb spec.c 'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'spec.o' failed make: [spec.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb thread.c'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'thread.o' failed make: [thread.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb zc_arraylist.c 'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'zc_arraylist.o' failed make: [zc_arraylist.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb zc_hashtable.c 'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'zc_hashtable.o' failed make: [zc_hashtable.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb zc_profile.c 'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'zc_profile.o' failed make: [zc_profile.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb zc_util.c 'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'zc_util.o' failed make: [zc_util.o] Error 1 (ignored) std=c99 -pedantic -c -O2 -fPIC -pthread -Wall -Wstrict-prototypes -fwrapv -g -ggdb zlog.c 'std' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 makefile:154: recipe for target 'zlog.o' failed make: [zlog.o] Error 1 (ignored) shared -Wl,-soname,libzlog.so.1.2 -o libzlog.so 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 -pthread process_begin: CreateProcess(NULL, shared -Wl,-soname,libzlog.so.1.2 -o libzlog.so 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 -pthread, ...) failed. make (e=2): makefile:137: recipe for target 'libzlog.so' failed make: [libzlog.so] Error 2 (ignored) # for use in test folder - linux and requirement for aix runtime process_begin: CreateProcess(NULL, # for use in test folder - linux and requirement for aix runtime, ...) failed. make (e=2): makefile:137: recipe for target 'libzlog.so' failed make: *** [libzlog.so] Error 2
在这种情况下,我们要不在linux下把这个开源库编译好,把编译好的库文件拿过来用;或者去找是否有编译好的发行版库文件。
所幸,我们找到了该开源库在Windows下的移植:WinZlog
cJSON是用来解析JSON字符串的,非常简单,当我们下载好cJSON只需要把.c和.h文件包含文件拷贝到我们工程目录下,并将头文件和实现文件包含进来就可以使用了!当然你也可以将其编译成库文件调用。
想要了解eJSON可以看这个:cJSON 解析
GitHub地址为:cJSON
因此该库因为非常简单,源文件非常少,所以,我们可以直接将这两个文件添加到我们的项目中直接使用。
推荐下面两篇:
GitHub地址:CMockery
博文:C单元测试框架——CMockery (1) 简介,CMockery