在Windows下使用nmake+Makefile+编译ZThread库(附例子)
----------2015/01/09/23:21更新-----------------------------------
关于保留DEBUG信息的一个简单例子,见这篇随笔
----------2014/12/18/17:53更新-----------------------------------
前段时间写了这篇随笔,现在回过头来看感觉有很多问题,因此打算修正和补充一下,以前写的内容也没删,就留在这篇随笔的最下面了,可以对比着看看
目的:编写使用ZThread库的多线程程序
Windows: (Win7)
因为ZThread是支持Windows平台的,所以windows下,最好用visual studio的编译器,确保最好的兼容性
安装visual studio之后,通过开始>所有程序>Visual Studio 2013>Visual Studio Tools>VS2013 开发人员命令提示就可以使用CL、LINK、LIB、NMAKE这几个Windows下的编译和生成工具了。(相当于GNU的g++、ar、make)。
编译ZThread
从sourceforge.net下载ZThread-2.3.2.tar.gz,解压到F:/libs/ZThread-2.3.2
查看README>查看BUILDING
* Any other method is up to you. There are simply too many compilers,
too many versions and too many platforms to maintain separate build files
for.BUT, this doesn't mean you are out of luck.
I have structured the code so that it is very simple to compile the library
however suits your needs best. All you need to do is include the .cxx files
in the src/ directory (not the subdirectories) in your build rule, and add the
include directory to your compilers include/ path.
打开terminal,切换到目录F:/libs/ZThread-2.3.2/src
输入命令:CL /c /I..\include *.cxx
也就是编译所有的cxx文件,并生成对应的obj文件,但是不调用LINK对obj文件进行链接(比如somebody.cxx会被编译为somebody.obj)
等价于GNU的:g++ -c -I ../include *.cxx
然后输入命令:LIB /OUT:ZThread_win32.lib *.obj
也就是将所有的obj文件打包为lib文件
等价于GNU的:ar -r ZThread.a *.o
注意此处必须用CL编译的obj文件,并且由LIB打包成lib文件,如果是其他编译器编译的.a文件,你改后缀名改成.lib在windows下是用不了的,会报很多undefined reference to xxx错误。总而言之你坚持一个原则:用GNU的工具生成的库,那么引用这个库的代码就必须用GNU的编译器来编译,如果是用windows的工具生成的库,那么引用这个库的代码就必须用windows的编译器来编译!一般来说,如果一个库只使用C++ Standard里面的东西,就是平台无关的,比如ZThread就是这样的库,这样的库在几乎任何支持C++ Standard的平台上都是可以编译的,只不过,你选择了哪个平台,你最好就用哪个平台的编译器!
好,第二步,写代码,代码结构如下(加粗的就代表文件夹)
zthreaddemo
libs
zthread
ZThread_win32.lib
include
zthread
// zthread的所有头文件
LiftOff.h
Test.h
src
LiftOff.cpp
Test.cpp
main.cpp
Makefile
代码我就不贴了,只贴Makefile的,你可以下载项目文件夹来看看
Makefile
# See
# http://msdn.microsoft.com/zh-cn/library/f35ctcxw.aspx
# for more info about Microsoft Visual C++ Compiler and Linker options # Microsoft Visual C++ Compiler && Linker tool
CC = cl
# Microsoft Visual C++ Linker
LINK = link # LIB_ZTHREAD is the ZThread static link library path
# /LIBPATH:<dir> Specifies a path that the linker will search before it searches the path specified in the LIB environment option. If you want to specify more than one directory, you must specify multiple /LIBPATH options.
# here we need the ZThread_win32.lib
LIB_ZTHREAD = /LIBPATH:libs\zthread # tells the linker where to find object files
OBJ_PATH = /LIBPATH:obj # '/I<PATH_NAME>' or '/I <PATH_NAME>' specifies a header search path
# for example: CL /I \xxinclude /I\my\include main.c
# tells the compiler where to find my own header files
# *** This makes you free from the burden to write things like #include "../include/xxx" in your cpp files ***
HEADER_PATH = /I include # See this page, search '/EHsc'
# http://wenku.baidu.com/view/04a34101de80d4d8d15a4ff2.html
EHSC = /EHsc # Compiles without linking.
COMPILATION_ONLY = /c # Compiler output object file: /Fo<PATH_NAME>, for example:
# cl /c hello.cpp /Foobj\hello.obj put the hello.obj file into the folder 'obj'
C_OUT = /Fo: # Linker output executable file
# note that the comma must be followed by the path WITHOUT any white-characters
L_OUT = /OUT: bin\test.exe: bin obj obj\main.obj obj\Test.obj obj\LiftOff.obj
$(LINK) $(LIB_ZTHREAD) $(OBJ_PATH) $(L_OUT)bin\test.exe main.obj Test.obj LiftOff.obj zthread_win32.lib
obj\main.obj: src\main.cpp include\Test.h
$(CC) $(EHSC) $(HEADER_PATH) $(COMPILATION_ONLY) src\main.cpp $(C_OUT)obj\main.obj obj\Test.obj: src\Test.cpp include\Test.h
$(CC) $(EHSC) $(HEADER_PATH) $(COMPILATION_ONLY) src\Test.cpp $(C_OUT)obj\Test.obj obj\LiftOff.obj: src\LiftOff.cpp include\LiftOff.h
$(CC) $(EHSC) $(HEADER_PATH) $(COMPILATION_ONLY) src\LiftOff.cpp $(C_OUT)obj\LiftOff.obj obj:
mkdir obj bin:
mkdir bin
# PHONY means 'clean' is a fake target
# use 'make clean' to remove all .obj files
# before rebuilding
# '-' means continue execute next command even if something goes wrong with this command
# type 'help' to get info about 'rmdir'
# type 'help rmdir' to get info about '/s' and '/q'
.PHONY: clean
clean:
-rmdir /s /q bin
-rmdir /s /q obj
这里面写了一些注释,看看可以帮助理解。总的思想就是:
先创建bin和obj文件夹,调用CL编译src里面的cpp文件,把生成的obj文件放到obj文件夹里,接着调用LINK链接所有的obj文件和lib文件,生成test.exe放到bin目录下.
要生成代码,所要做的工作就是打开VS2013 开发人员命令提示,然后切换到zthreaddemo目录中,输入命令nmake即可
里面有几个要点:
1、我将很多编译器和连接器的选项都写成了宏调用的形式,希望看起来可读性更好一些
2、注意文件的组织方式,src、include、libs、obj、bin这样的组织方式更整洁,src里面根据你的模块要求还可以设置子文件夹,include也是,libs里面根据你的需要也可以设置子文件夹,obj的组织结构一般与src是一一对应的(也就是说,如果你有src/xxx/yyy.cpp,那么生成obj文件的时候也应该有obj/xxx/yyy.obj)
3、类似于/OUT:这样的选项,冒号后面必须紧跟路径,中间不能有空格,而/I这个选项与路径之间,可以有空格也可以没空格
Linux: (Ubuntu)
编译ZThread,查看README, BUILDING
一般来说在类Unix环境下安装一个库的流程都是先./configure,再make,再make install。这样就可以
把头文件安装到/usr/local/include
把库文件(.a文件)安装到/usr/local/lib
把可执行文件安装到/usr/local/bin
但是我不知道是我的问题还是ZThread的configure代码的问题,./configure总是报错
所以我还是采取直接编译的方法,到/ZThread-2.3.2/src下运行命令g++ -I../include -fpermissive -c *.cxx
选项-fpermissive的作用是把一些error给改成warning.原因是ZThread的代码是比较陈旧的代码了,在目前的C++ Standard中过去的某些语法可能被编译器视为error,但是-fpermissive选项的意思就是告诉编译器:我确定这个代码格式没有语法或其他错误,只是比较陈旧不符合现代的标准而已。可以参考这个解释
选项-I../include是说zthread的头文件在上一级目录的include文件夹中
然后运行命令ar -r ZThread.a *.o
得到zthread.a
文件的组织方式仍然如前面所述
zthreaddemo
libs
zthread
ZThread.a
include
zthread
// zthread的所有头文件
LiftOff.h
Test.h
src
LiftOff.cpp
Test.cpp
main.cpp
Makefile
代码不变,只修改Makefile,如下所示(注意这里的Makefile与项目文件夹里的不太一样,以这里的为准)
# See
# http://www.gnu.org/software/gcc
# for more info about GNU C++ Compiler and Linker options # GNU C++ Compiler && Linker tool
CC = g++
# GNU C++ Linker
LINK = g++ # LIB_PATH tells the linker where to find library files
# -L <path> Specifies a path that the linker will search before it searches the path specified in the LIB environment option. If you want to specify more than one directory, you must specify multiple -L options.
# here we need the ZThread.a
LIB_PATH = -Llibs/zthread
# -l<LIBRARY_NAME> specifies a library file to link
# note that to use the '-l' flag, you must name
# your static library file libLIBRARY_NAME.a (the prefix 'lib'
# cannot be omitted) and use '-Ldir'
# before you actually using the '-l' flag, where 'dir'
# is the directory that your libxxx.a can be found
# immediately (can't be parent directory).
# You might think that it's verbose to say '-Llibs/zthread -lZThread',
# why not just say 'libs/zthread/ZThread.a' ?
# Yes in this case it's not a good example. But what if
# you put all your library files DIRECTLY in the folder 'libs'?
# Suppose you put libraryA.a libraryB.a libraryC.a DIRECTLY
# in the folder 'libs', you just need to specify '-Llibs' once,
# then you just say '-llibraryA' '-llibraryB' '-libraryC' to link
# all three library files.
LIB_FILE = -l # '-I<PATH_NAME>' specifies a header search path
# for example: g++ -I /xxinclude -I /my/include main.c
# tells the compiler where to find my own header files
# *** This makes you free from the burden to write things like #include "../include/xxx" in your cpp files ***
HEADER_PATH = -Iinclude # Compiles without linking.
COMPILATION_ONLY = -c # Compiler output object file: -o <PATH_NAME/object_file.o>, for example:
# g++ -c hello.cpp -o obj/hello.o put the hello.o file into the folder 'obj'
C_OUT = -o # Linker output executable file
L_OUT = -o bin/test: bin obj obj/main.o obj/Test.o obj/LiftOff.o
$(LINK) obj/main.o obj/Test.o obj/LiftOff.o $(LIB_PATH) -lZThread -lpthread $(L_OUT) bin/test
obj/main.o: src/main.cpp include/Test.h
$(CC) $(HEADER_PATH) $(COMPILATION_ONLY) src/main.cpp $(C_OUT) obj/main.o obj/Test.o: src/Test.cpp include/Test.h
$(CC) $(HEADER_PATH) $(COMPILATION_ONLY) src/Test.cpp $(C_OUT) obj/Test.o obj/LiftOff.o: src/LiftOff.cpp include/LiftOff.h
$(CC) $(HEADER_PATH) $(COMPILATION_ONLY) src/LiftOff.cpp $(C_OUT) obj/LiftOff.o obj:
mkdir obj bin:
mkdir bin
# PHONY means 'clean' is a fake target
# use 'make clean' to remove all .obj files
# before rebuilding
# '-' means continue execute next command even if something goes wrong with this command
# type 'rm --help' to get info about '-r' and '-f'
.PHONY: clean
clean:
-rm -r -f bin
-rm -r -f obj
---------------------------------------
2014/12/18更新之前的内容(已陈旧,有部分误区。尽量别看这个)
用mingw32-make就行了,语法跟GNU make基本上是一样的,只是要针对windows写命令,比如linux下的rm指令(删除文件)在windows下需要换成del指令
为什么不用Cygwin?——老爱报些莫名其妙的错误。下面举个例子
下面用LIB_ZTHREAD代指Windows下的F:/libs/zthread_win32.a或者Ubuntu下的/home/admin/libs/zthread.a
用HEADER_ZTHREAD代指Windows下的F:/libs/ZThread-2.3.2/include或者Ubuntu下的/home/admin/libs/ZThread-2.3.2/include
点此下载zthread_win32.a
点此下载zthread.a
文件结构:所有的.cpp文件.h文件Makefile都在一个文件夹里,假设其目录为TEST_DIR
源代码:
main.cpp
#include "Test.h" using namespace std; int main()
{
Test::testLiftOff();
return ;
}
Test.h
#ifndef TEST_H
#define TEST_H class Test
{
public:
static void testLiftOff(); private:
Test();
~Test();
}; #endif // TEST_H
Test.cpp
#include "Test.h" #include "LiftOff.h" #include <zthread/Thread.h> #include <iostream> // std::cout void Test::testLiftOff()
{
using namespace ZThread; try {
for (int i = ; i < ; ++i)
{
Thread th(new LiftOff(, i));
}
std::cout << "waiting for lift off" << std::endl;
} catch (Synchronization_Exception &e) {
std::cerr << e.what() << std::endl;
}
} Test::Test()
{
//ctor
} Test::~Test()
{
//dtor
}
LiftOff.h
#ifndef LIFTOFF_H
#define LIFTOFF_H #include <zthread/Runnable.h> class LiftOff : public ZThread::Runnable
{
public:
LiftOff(int countDown_, int id_);
~LiftOff();
void run();
private:
int countDown;
int id;
}; #endif // LIFTOFF_H
LiftOff.cpp
#include "LiftOff.h" #include <iostream> using namespace std; LiftOff::LiftOff(int countDown_, int id_)
:countDown(countDown_), id(id_)
{
// do nothing
} LiftOff::~LiftOff()
{
cout << "LiftOff" << id << " destroyed" << endl;
} void LiftOff::run()
{
while (countDown--)
cout << id << " count: " << countDown << endl;
cout << id << "LiftOff!" << endl;
}
1. Ubuntu (linux) + GNU make
Makefile
# ZTHREAD_A the static link library file of ZThread
ZTHREAD_A = /home/admin/libs/zthread.a # ZTHREAD_H is the directory that has all the header
# files of the ZThread library
ZTHREAD_H = /home/admin/libs/ZThread-2.3.2/include
test.exe: main.o Test.o LiftOff.o
g++ -o test.exe main.o Test.o LiftOff.o -s $(ZTHREAD_A) -lpthread # -lpthread is necessary to link pthread library, which is not part of the default library in Ubuntu, ZThread need pthread support
main.o: main.cpp
g++ -c main.cpp -o main.o
# '-I' specifies the header search directory
Test.o: Test.cpp Test.h
g++ -I $(ZTHREAD_H) -c Test.cpp -o Test.o
LiftOff.o: LiftOff.cpp LiftOff.h
g++ -I $(ZTHREAD_H) -c LiftOff.cpp -o LiftOff.o # PHONY means 'clean' is a fake target
# use 'make clean' to remove all .o files
# before rebuilding
.PHONY: clean
clean:
-rm test # '-' means continue execute next command even if something goes wrong
-rm *.o
make clean
make -f Makefile
运行成功
2. Windows + mingw32-make
Makefile
# ZTHREAD_A the static link library file of ZThread
ZTHREAD_A = F:/libs/ZThread-2.3./lib/zthread_win32.a
# ZTHREAD_H is the directory that has all the header
# files of the ZThread library
ZTHREAD_H = F:/libs/ZThread-2.3./include test.exe: main.o Test.o LiftOff.o
g++ -o test.exe main.o Test.o LiftOff.o -s $(ZTHREAD_A)
main.o: main.cpp
g++ -c main.cpp -o main.o
# '-I' specifies the header search directory
Test.o: Test.cpp Test.h
g++ -I $(ZTHREAD_H) -c Test.cpp -o Test.o
LiftOff.o: LiftOff.cpp LiftOff.h
g++ -I $(ZTHREAD_H) -c LiftOff.cpp -o LiftOff.o # PHONY means 'clean' is a fake target
# use 'make clean' to remove all .o files
# before rebuilding
# '-' means continue execute next command even if something goes wrong with this command
.PHONY: clean
clean:
-del test.exe
-del *.o
mingw32-make clean
mingw32-make -f Makefile
运行成功
3. Windows + Cygwin
Makefile
# ZTHREAD_A the static link library file of ZThread
ZTHREAD_A = F:/libs/ZThread-2.3./lib/zthread_win32.a
# ZTHREAD_H is the directory that has all the header
# files of the ZThread library
ZTHREAD_H = F:/libs/ZThread-2.3./include test.exe: main.o Test.o LiftOff.o
g++ -o test.exe main.o Test.o LiftOff.o -s $(ZTHREAD_A)
main.o: main.cpp
g++ -c main.cpp -o main.o
# '-I' specifies the header search directory
Test.o: Test.cpp Test.h
g++ -I $(ZTHREAD_H) -c Test.cpp -o Test.o
LiftOff.o: LiftOff.cpp LiftOff.h
g++ -I $(ZTHREAD_H) -c LiftOff.cpp -o LiftOff.o # PHONY means 'clean' is a fake target
# use 'make clean' to remove all .o files
# before rebuilding
# '-' means continue execute next command even if something goes wrong with this command
.PHONY: clean
clean:
-rm test.exe
-rm *.o
make clean没问题
make报错(貌似是找不到__assert的实现,真心无语),报错的详细信息见这篇随笔
在Windows下使用nmake+Makefile+编译ZThread库(附例子)的更多相关文章
- windows下如何使用makefile编译
1. 编写makefile. 2. 使用nmake进行编译, vs2010或者其他都是用nmake进行编译的,将bin目录添加到path环境变量中 先执行vcvars32.bat 再执行nmake
- 在Windows下搭建C++11 编译环境(附下载,包括mingw-build,TDM-GCC, nuwen MinGW Distro)
由于现实的一些原因,并不是所有人都能很方便的享受到C++11 特性.特别是C++ Primer 第五版 和 The C++ Programming Language 第四版等全面C++ 11 铺开以后 ...
- 在Windows下使用MinGW静态编译Assimp
使用MinGW静态编译Assimp 到了5月份了,没有写一篇日志,于是自己从知识库里面拿出一篇文章充数吧.这次将要解说怎样在Windows下使用MinGW静态编译Assimp. Assimp是眼下比較 ...
- 在Windows下使用CodeBlock使用libiconv第三方库
在Windows下使用CodeBlock使用libiconv第三方库 1. 选择在Project->Build options下: 2. 如下图添加libicon ...
- 【VS开发】【数据库开发】libevent windows下基于VS2010的编译
libevent是一个常用的网络库,下面就看看在windows下面编译测试的过程吧. 一 环境 系统:win8.1编译器:VS2013官方下载地址:http://libevent.org/版本:2.0 ...
- 开源项目:windows下使用MinGW+msys编译ffmpeg
本文参考了网络上的不少文章,但由于版本环境的问题参考文章并不能直接指导编译,本文吸收多方经验,并在自己多次编译实验的基础上写成,欢迎转载,请注名出处. FFmpeg是在Linux平台下开发的,但 ...
- windows 下使用 MinGW + msys 编译 ffmpeg
本文参考了网络上的不少文章,但由于版本环境的问题参考文章并不能直接指导编译,本文吸收多方经验,并在自己多次编译实验的基础上写成,欢迎转载,请注名出处. FFmpeg是在Linux平台下开发的,但 ...
- Windows下Visual studio 2013 编译 Audacity
编译的Audacity版本为2.1.2,由于实在windows下编译,其源代码可以从Github上取得 git clone https://github.com/audacity/audacity. ...
- 几款比较好用的C语言的集成开发环境及在windows下用命令行编译C代码
最近要用到C,所以尝试了这几款windows平台下比较好的IDE. VS2015:比较复杂和庞大,据说从2013版本开始支持C99标准. C-free:轻巧,但是不支持C99. vc++6.0:很多学 ...
随机推荐
- javascript正则中ASCII与unicode
正则表达式中允许直接利用ASCII和Unicode编码来查找我们相应的字符串. ASCII: 下面是检索ASCII编码在x41-x7a范围内的所有匹配的字符串.(x41,x7a为十六进制) var s ...
- Android-Universal-Image-Loader载入图片
直接看代码:MainActivity: package com.example.textwsjdemo; import com.nostra13.universalimageloader.cache. ...
- MYSQL LIMIT 用法详解
在mysql的limit用法中,网上有这样的论述: "//为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1: mysql>SELECT * FROM tab ...
- [转]SSIS: By coding
本文转自:http://www.codeproject.com/Articles/604197/SSIS-By-coding Introduction SSIS better known as “SQ ...
- linux xfs文件系统无法用readdir获取dirent文件类型d_type则用stat获取暨stat函数讲解
stat函数讲解 表头文件: #include <sys/stat.h> #include <unistd.h>定义函数: int stat ...
- C++ 初始化列表(转载)
何谓初始化列表 与其他函数不同,构造函数除了有名字,参数列表和函数体之外,还可以有初始化列表,初始化列表以冒号开头,后跟一系列以逗号分隔的初始化字段.在 C++中,struct和class的唯一区别是 ...
- IOS生成证书
1.生成本地签名文件, 点击此图标,选择证书助理,按照以下步骤生成签名文件,在生成证书时需要导入签名文件生成. 点击继续就能生成签名文件,保存次CSR文件. 2.生成证书 到下面这个页面选择证书的签名 ...
- web页面内容优化管理与性能技巧
来源:GBin1.com 回 想一下,以前我们不得不花费大量时间去优化页面内容(图片.CSS等等),如今用户有更快速的互联网链接,我们似乎能够使用更大的图像或更大的闪 存文件,里面包含的有视频或者图片 ...
- Solidworks如何让齿轮运动副保证持续啮合状态
出现这种情况一般是齿轮的比例有问题,如果你选择两个齿轮的齿顶圆的面,则自动比例是44:74,然后手动转动某个齿轮,就会出现不能啮合的情况 只要模数相同的齿轮不管大小都能始终啮合,但是你需要首先为每 ...
- C#中怎样获取当前路径的几种方法
String apppath = System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase; //获取整个文件路径名 a ...