在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

1 #include "Test.h"
2 
3 using namespace std;
4 
5 int main()
6 {
7     Test::testLiftOff();
8     return 0;
9 }

 

Test.h

 1 #ifndef TEST_H
 2 #define TEST_H
 3 
 4 
 5 class Test
 6 {
 7     public:
 8         static void testLiftOff();
 9 
10     private:
11         Test();
12         ~Test();
13 };
14 
15 #endif // TEST_H

 

Test.cpp

 1 #include "Test.h"
 2 
 3 #include "LiftOff.h"
 4 
 5 #include <zthread/Thread.h>
 6 
 7 #include <iostream>       // std::cout
 8 
 9 void Test::testLiftOff()
10 {
11     using namespace ZThread;
12 
13     try {
14         for (int i = 0; i < 5; ++i)
15         {
16             Thread th(new LiftOff(10, i));
17         }
18         std::cout << "waiting for lift off" << std::endl;
19     } catch (Synchronization_Exception &e) {
20         std::cerr << e.what() << std::endl;
21     }
22 }
23 
24 Test::Test()
25 {
26     //ctor
27 }
28 
29 Test::~Test()
30 {
31     //dtor
32 }

 

LiftOff.h

 1 #ifndef LIFTOFF_H
 2 #define LIFTOFF_H
 3 
 4 #include <zthread/Runnable.h>
 5 
 6 class LiftOff : public ZThread::Runnable
 7 {
 8     public:
 9         LiftOff(int countDown_, int id_);
10         ~LiftOff();
11         void run();
12     private:
13         int countDown;
14         int id;
15 };
16 
17 #endif // LIFTOFF_H

 

LiftOff.cpp

 1 #include "LiftOff.h"
 2 
 3 #include <iostream>
 4 
 5 using namespace std;
 6 
 7 LiftOff::LiftOff(int countDown_, int id_)
 8     :countDown(countDown_), id(id_)
 9 {
10     // do nothing
11 }
12 
13 LiftOff::~LiftOff()
14 {
15     cout << "LiftOff" << id << " destroyed" << endl;
16 }
17 
18 void LiftOff::run()
19 {
20     while (countDown--)
21         cout << id << " count: " << countDown << endl;
22     cout << id << "LiftOff!" << endl;
23 }

 

 

1. Ubuntu (linux) + GNU make

Makefile

 1 # ZTHREAD_A the static link library file of ZThread
 2 ZTHREAD_A = /home/admin/libs/zthread.a 3 # ZTHREAD_H is the directory that has all the header
 4 # files of the ZThread library
 5 ZTHREAD_H = /home/admin/libs/ZThread-2.3.2/include 6 
 7 test.exe: main.o Test.o LiftOff.o
 8     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
 9 main.o: main.cpp
10     g++ -c main.cpp -o main.o
11 # '-I' specifies the header search directory
12 Test.o: Test.cpp Test.h
13     g++ -I $(ZTHREAD_H) -c Test.cpp -o Test.o
14 LiftOff.o: LiftOff.cpp LiftOff.h
15     g++ -I $(ZTHREAD_H) -c LiftOff.cpp -o LiftOff.o
16 
17 # PHONY means 'clean' is a fake target
18 # use 'make clean' to remove all .o files
19 # before rebuilding
20 .PHONY: clean
21 clean:
22     -rm test # '-' means continue execute next command even if something goes wrong
23     -rm *.o

 

make clean

make -f Makefile

运行成功

 

2. Windows + mingw32-make

Makefile

 1 # ZTHREAD_A the static link library file of ZThread
 2 ZTHREAD_A = F:/libs/ZThread-2.3.2/lib/zthread_win32.a
 3 # ZTHREAD_H is the directory that has all the header
 4 # files of the ZThread library
 5 ZTHREAD_H = F:/libs/ZThread-2.3.2/include
 6 
 7 test.exe: main.o Test.o LiftOff.o
 8     g++ -o test.exe main.o Test.o LiftOff.o -s $(ZTHREAD_A)
 9 main.o: main.cpp
10     g++ -c main.cpp -o main.o
11 # '-I' specifies the header search directory
12 Test.o: Test.cpp Test.h
13     g++ -I $(ZTHREAD_H) -c Test.cpp -o Test.o
14 LiftOff.o: LiftOff.cpp LiftOff.h
15     g++ -I $(ZTHREAD_H) -c LiftOff.cpp -o LiftOff.o
16 
17 # PHONY means 'clean' is a fake target
18 # use 'make clean' to remove all .o files
19 # before rebuilding
20 # '-' means continue execute next command even if something goes wrong with this command
21 .PHONY: clean
22 clean:
23     -del test.exe
24     -del *.o

 

mingw32-make clean

mingw32-make -f Makefile

运行成功

 

3. Windows + Cygwin

Makefile

 1 # ZTHREAD_A the static link library file of ZThread
 2 ZTHREAD_A = F:/libs/ZThread-2.3.2/lib/zthread_win32.a
 3 # ZTHREAD_H is the directory that has all the header
 4 # files of the ZThread library
 5 ZTHREAD_H = F:/libs/ZThread-2.3.2/include
 6 
 7 test.exe: main.o Test.o LiftOff.o
 8     g++ -o test.exe main.o Test.o LiftOff.o -s $(ZTHREAD_A)
 9 main.o: main.cpp
10     g++ -c main.cpp -o main.o
11 # '-I' specifies the header search directory
12 Test.o: Test.cpp Test.h
13     g++ -I $(ZTHREAD_H) -c Test.cpp -o Test.o
14 LiftOff.o: LiftOff.cpp LiftOff.h
15     g++ -I $(ZTHREAD_H) -c LiftOff.cpp -o LiftOff.o
16 
17 # PHONY means 'clean' is a fake target
18 # use 'make clean' to remove all .o files
19 # before rebuilding
20 # '-' means continue execute next command even if something goes wrong with this command 
21 .PHONY: clean
22 clean:
23     -rm test.exe
24     -rm *.o

make clean没问题

make报错(貌似是找不到__assert的实现,真心无语),报错的详细信息见这篇随笔

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值