如何自己编译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\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进行了下突击:

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的更多相关文章
- 关于apue.3e中apue.h的使用
关于apue.3e中apue.h的使用 近来要学一遍APUE第三版,并于此开博做为记录. 先下载源文件: # url: http://http//www.apuebook.com/code3e.htm ...
- 学习编译并运行C代码
以<UNIX网络编程>中的代码为例,学习如何编译并运行C代码. 根据 UNIX网络编程(第3版)环境搭建——使用MAC OSX10.10,能够成功运行 1.下载本书的头文件及示例源码原书地 ...
- Lua 学习笔记(七)编译、执行外部代码块
Lua称为解释型语言的原因:Lua允许在运行源代码之前,先将源代码预编译为一种中间形式.区别解释型语言的主要特征是在于编译器是否是语言运行时库的一部分,即有能力执行动态生成的代码.因为Lua中有dof ...
- 利用Roslyn把C#代码编译到内存中并进行执行
Tugberk Ugurlu在其博文<Compiling C# Code Into Memory and Executing It with Roslyn>中给大家介绍了一种使用.NET下 ...
- Java中String的intern方法,javap&cfr.jar反编译,javap反编译后二进制指令代码详解,Java8常量池的位置
一个例子 public class TestString{ public static void main(String[] args){ String a = "a"; Stri ...
- apue.3e 的安装 (基于ubuntu12.0.4)
本菜刚刚学习UNIX下高级编程,无奈搭建本书编程环境时遇到不少问题.幸好网上有各种大神的解决办法让我最终解决了问题.在这里感谢为LINUX开源操作系统奋斗的大神. 不过话说回来,网上大都是针对UNIX ...
- 【APUE】Chapter16 Network IPC: Sockets & makefile写法学习
16.1 Introduction Chapter15讲的是同一个machine之间不同进程的通信,这一章内容是不同machine之间通过network通信,切入点是socket. 16.2 Sock ...
- PHP实例开发(3)PHP中MVC学习之ThinkPHP
PHP中MVC学习之ThinkPHP 1.什么是MVC MVC本来是存在于Desktop程序中的,M是指数据模型,V是指用户界面,C则是控制器.使用MVC的目的是将M和V的实现代码分离 MVC是一个设 ...
- 转:openwrt中luci学习笔记
原文地址:openwrt中luci学习笔记 最近在学习OpenWrt,需要在OpenWrt的WEB界面增加内容,本文将讲述修改OpenWrt的过程和其中遇到的问题. 一.WEB界面开发 ...
随机推荐
- 西门子 S7-1500 PLC,使用手轮控制伺服电机
西门子 S7-1500 PLC,使用手轮控制伺服电机 本文描述了一种,1500PLC使用叠加定位的方法,实现手轮操作的方法. 手轮操作需要的功能 数控机床等设备上的电子手轮,起源于机械手轮.机械手轮是 ...
- Git-实验报告
“Git 实战教程”实验报告 基本用法(下) 二.比较内容 1.比较提交 - Git Diff git diff命令的作用是比较修改的或提交的文件内容. 如何查看缓存区内与上次提交之间的差别呢?需要使 ...
- Design and Implementation of Global Path Planning System for Unmanned Surface Vehicle among Multiple Task Points
Design and Implementation of Global Path Planning System for Unmanned Surface Vehicle among Multiple ...
- js控制select选中显示不同表单内容
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- react(二):组件的通信
对于组件来说,通信无非两种,父子组件通信,和非父子组件通信 一.父子父子组件通信 1.父组件给子组件传值 对于父组件来说,props是他们之间的媒介 class Parent extends Comp ...
- django模板层(templates)
1.基础部分 通过使用模板,就可以在URL中直接调用HTML,它还是松耦合的,灵活性强,而且更容易维护 而且可以将变量通过一定的方式嵌入到HTML中,最终渲染到页面,总的来说基于模板完成了数据与用户之 ...
- 第34-2题:LeetCode113. Path Sum II
题目 给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径. 说明: 叶子节点是指没有子节点的节点. 示例: 给定如下二叉树,以及目标和 sum = 22, 5 / \ ...
- finddler的安装与设置
这是抓取手机包的设置 过滤 新安装的,可能还需要证书问题
- 介绍hadoop中的hadoop和hdfs命令
有些hive安装文档提到了hdfs dfs -mkdir ,也就是说hdfs也是可以用的,但在2.8.0中已经不那么处理了,之所以还可以使用,是为了向下兼容. 本文简要介绍一下有关的命令,以便对had ...
- 转:比较spring cloud和dubbo,各自的优缺点是什么
原文:https://blog.csdn.net/u010664947/article/details/80007767 dubbo由于是二进制的传输,占用带宽会更少 springCloud是http ...