本来是搜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\n"));
return ((void *));
} void * thr_fn2(void *arg)
{
printf(("thread 2 exiting"));
pthread_exit((void *));
} 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 ;
}

但马上觉得上述的代码有问题:如果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去做,就要把每个环节都搞清楚。这个光靠实践不行,还得去系统的学学,比如《程序员的自我修养》这本书就是非常好的内容。遂决定读。

如何自己编译apue.3e中代码 & 学习写makefile的更多相关文章

  1. 关于apue.3e中apue.h的使用

    关于apue.3e中apue.h的使用 近来要学一遍APUE第三版,并于此开博做为记录. 先下载源文件: # url: http://http//www.apuebook.com/code3e.htm ...

  2. 学习编译并运行C代码

    以<UNIX网络编程>中的代码为例,学习如何编译并运行C代码. 根据 UNIX网络编程(第3版)环境搭建——使用MAC OSX10.10,能够成功运行 1.下载本书的头文件及示例源码原书地 ...

  3. Lua 学习笔记(七)编译、执行外部代码块

    Lua称为解释型语言的原因:Lua允许在运行源代码之前,先将源代码预编译为一种中间形式.区别解释型语言的主要特征是在于编译器是否是语言运行时库的一部分,即有能力执行动态生成的代码.因为Lua中有dof ...

  4. 利用Roslyn把C#代码编译到内存中并进行执行

    Tugberk Ugurlu在其博文<Compiling C# Code Into Memory and Executing It with Roslyn>中给大家介绍了一种使用.NET下 ...

  5. Java中String的intern方法,javap&cfr.jar反编译,javap反编译后二进制指令代码详解,Java8常量池的位置

    一个例子 public class TestString{ public static void main(String[] args){ String a = "a"; Stri ...

  6. apue.3e 的安装 (基于ubuntu12.0.4)

    本菜刚刚学习UNIX下高级编程,无奈搭建本书编程环境时遇到不少问题.幸好网上有各种大神的解决办法让我最终解决了问题.在这里感谢为LINUX开源操作系统奋斗的大神. 不过话说回来,网上大都是针对UNIX ...

  7. 【APUE】Chapter16 Network IPC: Sockets & makefile写法学习

    16.1 Introduction Chapter15讲的是同一个machine之间不同进程的通信,这一章内容是不同machine之间通过network通信,切入点是socket. 16.2 Sock ...

  8. PHP实例开发(3)PHP中MVC学习之ThinkPHP

    PHP中MVC学习之ThinkPHP 1.什么是MVC MVC本来是存在于Desktop程序中的,M是指数据模型,V是指用户界面,C则是控制器.使用MVC的目的是将M和V的实现代码分离 MVC是一个设 ...

  9. 转:openwrt中luci学习笔记

    原文地址:openwrt中luci学习笔记 最近在学习OpenWrt,需要在OpenWrt的WEB界面增加内容,本文将讲述修改OpenWrt的过程和其中遇到的问题. 一.WEB界面开发         ...

随机推荐

  1. IOS NSOperationQueue(线程 封装操作)

    #import "HMViewController.h" @interface HMViewController () @end @implementation HMViewCon ...

  2. Linux ELF格式分析

    http://www.cnblogs.com/hzl6255/p/3312262.html ELF, Executable and Linking Format, 是一种用于可执行文件.目标文件.共享 ...

  3. jade文档声明和头尾标签

    作为一个页面,首先需要一个doctype的声明,它位于文档最上面的位置,放置html标签以前,用来告知浏览器当前这个页面用哪种html,或者xml的规范并解析页面   doctype html htm ...

  4. 5、Oracle备份(oracle备份脚本配置)

    1.1 Oracle数据库备份 1.1.1 链接Oracle介质管理库 请在数据库节点上操作. [oracle@db01/usr/openv/netbackup/bin]$ ./oracle_link ...

  5. C#自动更新本地程序

    关于系统的自动更新.近日有一情况是需要将java端后台最新版本的系统文件覆盖本地客户端,简称自动更新了. 本地会获取当前系统的版本号去请求后台java的接口数据.返回给我的是后台压缩包转的base64 ...

  6. C语言文件操作类型速查

    文件使用方式 含义 "r"(只读) 为输入打开一个文本文件,不存在则失败 "w"(只写) 为输出打开一个文本文件,不存在则新建,存在则删除后再新建 " ...

  7. iPad游戏 Calcculator: The Game 程序自动计算求解方法

    今天在iPad上下了个小游戏,主要是一个计算器的界面,有开始值,目标值,限定步数,以及一些加减乘除,还有作者脑洞想出来的功能键,主要有左移,直接把一个数加到末尾,将其中的某个数改为另一个数等等..玩到 ...

  8. Python 初始—(字符编码解码)

    字符编码之间的编码转换则需要通过Unicode 进行转换,那么需要一个编码和解码实现与Unicode进行关联转换 例如utf-8转gbk utf-8----decode----->Unicode ...

  9. python生成xml文件

    先上代码: #!/usr/bin/env python3 # _*_ coding: utf-8 _*_ from xml.dom.minidom import Document def readFi ...

  10. 网上商城_数据库jar包的使用

    网上商城_数据库jar包的使用 0.导入数据库相关jar包 commons-dbutils-1.4.jar c3p0-0.9.1.2.jar 1.配置C3P0-config.xml文件 <?xm ...