如何本身编译apue.3e中代码 & 学习写makefile

原本是搜pthread的相关资料,看blog发现不少linux程序员都看的一本神书《APUE》,里面有系统的两章内容专门讲pthread(不过是用c语言作的代码示例,这个不碍事,仍是归到原来linux c++分类中了),决定把这本书打印出来,过一下这两章内容。这个系列后面的日志会根据APUE书中的内容来。html

 

这篇日志说的内容与APUE没有直接关系,可是倒是由APUE引起的。python

 

背景是这样的linux

(1)对于我这个只在windows下用vs等IDE写过一些c程序,不知道gcc是干啥的人来讲,在unix下搞c就有困难(这个感受有点儿相似于只学过开自动挡的汽车,一会儿让你开手动挡了)。c++

(2)上来APUE的第一个demo就不能编译经过,由于APUE的全部demo代码中都包含一行include “apue.h”。翻开/apue/include/apue.h看了一眼:都是一些宏定义和函数声明,一些函数的具体实现都在/apue/lib/中了。这些东西怎么整合起来?之前在windows下好像都是用IDE创建一个工程,剩下的都是IDE给作好了。可是如今用的mac,未来在公司要用的是Linux,学会在linux下开发c c++的工程项目是迟早的事情,躲不开。程序员

(3)若是是python这种脚本语言,只要有python解释器就OK了;可是c语言这种强类型的语言的源代码是如何变成可执行的二进制文件的?这个问题我也说不清楚。(非计算机科班出身,没学过编译原理shell

上面的三个问题,恐怕也是不少只在win下开发过程序的人遇到的问题,而我就是其中一员。下面记录下解决上面困难的过程。macos

 

记录一下遇到的各类问题,经过查阅资料和推理一点儿点儿摸索着解决了(纯本身记录,非小白可直接忽略,不敢浪费你们时间)ubuntu

(一)gcc -I(搞清楚include "..."windows

原书的demo中 第一行是include "apue.h",但本身意识到“apue.h”不在当前路径下,应该把apue.h所在的路径完整写出来。 因而照猫画虎的代码以下:编辑器

#include "../apue.3e/include/apue.h"
#include <pthread.h>

void * thr_fn1(void *arg)
{
    printf(("thread 1 returning\n"));
    return ((void *)1);
}

void * thr_fn2(void *arg)
{
    printf(("thread 2 exiting"));
    pthread_exit((void *)2);
}

int main(int argc, char const *argv[])
{
    int err;
    pthread_t tid1, tid2;
    void *tret;
    err = pthread_create(&tid1, NULL, thr_fn1, NULL);
    err_exit(err, "can't");
    return 0;
}

但立刻以为上述的代码有问题:若是apue.h的路径改了,那岂不是全部源代码中的include “apue.h”都要跟着改?这样确定不科学。

因而查阅了一下gcc命令(http://blog.sina.com.cn/s/blog_57295811010008pj.html),知道了-I这个选项,能够把include "..."包含的文件路径放在-I后面。因而作了以下修改:

#include "apue.h"

并执行命令:gcc -I../apue.3e/include 11.3.c -pthread

获得了以下结果:

报错的内容就是说err_exit()这个函数找不到吧(这个时候不知道ld是什么意思,linker是啥也不知道

因而推理一下:多是只有apue.h头文件,gcc的过程当中没有找到实际函数实现吧。

去翻翻发现apue.h中有一句话:

void    err_exit(int, const char *, ...) __attribute__((noreturn));

这就是一句函数声明。

那么函数实体在哪里呢?到这里有点儿瞎,由于原书给的文件很大,那么多的文件上哪找err_exit呢?

即便找到的err_exit()的函数定义,又怎么让包含err_exit()函数定义的这个文件与demo文件合在一块儿呢?线索断了。

(二)make命令以及Makefile (在unix下本身完成win下IDE完成的事情)

接着(一),瞎查了半天没有什么结果,纠结了一下子。

一个偶然的想法让我在解决问题的路上去学了下make以及Makefile。

因为书上的demo毕竟是在ubuntu上运行的,而个人电脑是mac系统,虽然说都是unix,可是会不会是个人系统有问题或者gcc版本这类的问题致使不能编译经过呢?因而,我就想试试,能不能在APUE提供的源代码目录下编译经过呢?

这时候,我找到了APUE提供的源码文件夹中的Makefile文件,以下:

ROOT=..
EXTRALIBS=-pthread
PLATFORM=$(shell $(ROOT)/systype.sh)
include $(ROOT)/Make.defines.$(PLATFORM)

BAR =
ifeq "$(PLATFORM)" "macos"
  TLOCK =
  EXTRALIBS=-pthread
else
  TLOCK = timedlock
endif
ifeq "$(PLATFORM)" "linux"
  BAR = barrier
  EXTRALIBS=-pthread -lrt -lbsd
endif
ifeq "$(PLATFORM)" "freebsd"
  BAR = barrier
  EXTRALIBS=-pthread
endif
ifeq "$(PLATFORM)" "solaris"
  BAR = barrier
  EXTRALIBS=-lpthread -lrt
endif

PROGS = badexit2 cleanup exitstatus threadid

all:    $(PROGS) condvar.o maketimeout.o mutex1.o mutex2.o mutex3.o rwlock.o $(TLOCK) $(BAR)

$(PROGS):    $(LIBAPUE)
        $(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS) $(LDLIBS)

clean:
    rm -f $(PROGS) $(TEMPFILES) *.o $(TLOCK) $(BAR)

include $(ROOT)/Make.libapue.inc

以前据说过,Makefile貌似是告诉系统去怎么编译源代码这类的。因而,上网搜了以下的资料,对make和Makefile进行了下突击:

中文的blog:
youtube上的20分钟视频:
视频中提到的能够查阅的规范资料: http://www.gnu.org/software/make/manual/make.html
OK,看过上面的内容,我就试试在这个文件夹下直接make吧。获得了下面的结果:
编译经过了!而且运行了可执行文件,也与书中的结果同样。
这就证实了,这个demo源代码是能够被正确编译调试的,确定是我中间哪一个环节没弄对。线索又续上了。
 
(三)gcc -L -l (连接的过程)
接着(二),上图中执行make命令是对pthreads这一章全部demo的源代码进行编译了,我从中抽出来了关心的那一条:
gcc -ansi -I../include -Wall -DMACOS -D_DARWIN_C_SOURCE  threadid.c -o threadid  -L../lib -lapue -pthread

本身运行的命令照比make执行的命令主要少了红字的那一块。原来,是-L -l告诉了gcc,函数err_exit()的具体实如今哪里的啊。

==================================================

插播:忽然想起来本身买过一本书《程序员的自我修养》,里面讲了编译、连接什么的。

因而赶忙读了读,搞清楚点儿。也是在那本书中,知道了“连接”是一个很重要的过程,把

不一样模块拼在一块儿组成最后的完整的程序。

插播结束。

==================================================

-l后面接的“apue”应该是库文件的名字(linux静态库文件通常以libXXX.a的形式,XXX就是-l后面跟着的名字),因而天然就想看看这个apue库文件的样子

(四)sublime的陷阱 (有些格式的文件,sublime不显示

先找了下原书提供的代码文件中的lib文件夹;果真,找到了err_exit()函数的实现文件:error.c

你们能够看到,本人用的编辑器是sublime text2。为何要提一下这个编辑器?后面立刻说,如何被编辑器的设置给坑了。

看看sublime左侧边栏中,lib文件夹下也没有这样的文件啊,难倒还有其余的坑么?到这里又有些纠结了

(1)如今源文件所在目录已经找到了

(2)也知道-L把外部的库文件路径告诉gcc,-l告诉gcc应该具体用哪一个库文件

因而我在网上搜了一下(如这篇blog,http://www.cnblogs.com/showna/articles/1013399.html),库文件确实都是lib开头,.a .dylib结尾的这类啊。难倒库文件在lib文件夹中丢了?仍是有其余的说道?。

正在郁闷的时候,用iTerm命令行进入了lib文件夹下面,忽然展示了惊人的一幕:

喵了个咪的,这个apue库文件.a、编译后的目标文件.o都有啊!原来只是sublime的左边栏中没有这些.o和.a文件啊。

因而,知道被sublime给坑了。很快上网搜到了缘由,在sublime的Preferences选中中有以下的几行默认配置:

在sublime默认中,.a .o .lib这些扩展名的文件都不显示啊!!!

 

到了这里,终于把这一系列问题搞清楚了(这个过程大概持续了一白天),总结下缘由:

(1)对编辑器特性不熟悉(不知道有些文件还自动过滤了不显示),这个只能靠实践去磨了

(2)对于程序由源代码到可执行文件的原理不了解。之前在windows平台不少事情都VS作了,用Eclipse写Java就更省事儿了;如今须要本身写Makefile去作,就要把每一个环节都搞清楚。这个光靠实践不行,还得去系统的学学,好比《程序员的自我修养》这本书就是很是好的内容。遂决定读。

相关文章
相关标签/搜索