zoukankan      html  css  js  c++  java
  • 如何自己编译apue.3e中代码 & 学习写makefile

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

    这篇日志说的内容与APUE没有直接关系,但是却是由APUE引发的。

    背景是这样的

    (1)对于我这个只在windows下用vs等IDE写过一些c程序,不知道gcc是干啥的人来说,在unix下搞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语言这种强类型的语言的源代码是如何变成可执行的二进制文件的?这个问题我也说不清楚。(非计算机科班出身,没学过编译原理

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

    记录一下遇到的各种问题,通过查阅资料和推理一点儿点儿摸索着解决了(纯自己记录,非小白可直接忽略,不敢浪费大家时间)

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

    原书的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
    "));
        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去做,就要把每个环节都搞清楚。这个光靠实践不行,还得去系统的学学,比如《程序员的自我修养》这本书就是非常好的内容。遂决定读。

  • 相关阅读:
    使用ant部署web项目
    搭建ant环境
    Myeclipse8.5,9.0安装svn插件
    自定义任务扩展 ANT
    使用jmeter测试 webservice
    随机数猜1-9的数字
    线性表
    显示所有线性元素
    新学到的继承链
    计算圆
  • 原文地址:https://www.cnblogs.com/xbf9xbf/p/4755458.html
Copyright © 2011-2022 走看看