OS X下搭建虚拟Hadoop 2.5开发环境

在此记录OS X下搭建虚拟Hadoop 2.5开发环境,这包括了:

  1. Hadoop 2.5的安装、配置
  2. 访问Hadoop文件系统和运行样例
  3. Intellij IDEA中创建Hadoop依赖的项目

注意,OS X并不被Hadoop官方支持,因此仅可作为开发环境。

0. 基本配置

  • OS X Yosemite 10.10.1
  • JDK 1.7
  • Hadoop 2.5.1 (from Homebrew)
  • Intellij IDEA 13 CE

1. 安装和配置

  1. Homebrew安装Hadoop

     brew install hadoop
    

    Homebrew包默认安装至/usr/local/Cellar/hadoop目录中, 本文中安装的版本为Hadoop 2.5.2。

    Hadoop从2.3版本开始引入Yarn核心,配置方式与此前版本不同。

  2. 进入配置文件目录

     cd /usr/local/Cellar/hadoop/2.5.2/libexec/etc/hadoop
    
  3. 修改core-site.xml

    <configuration>节点内添加以下配置。

     <property>
         <name>hadoop.tmp.dir</name>
         <value>/Users/you_username/hadoop/tmp/hadoop-${user.name}</value>
     </property>
     <property>
         <name>fs.defaultFS</name>
         <value>hdfs://localhost:9000</value>
     </property>
    
    • hadoop.tmp.dir: HDFS文件系统的存放位置,需要指定一个已 存在并有读写权限的文件夹。不过路径最后 一项是Hadoop自己创建的。

    • fs.defaultFS: HDFS位置,写本机地址,9000是默认端口,可 省略。

  4. 修改hdfs-site.xml

     <property>
         <name>dfs.repliacation</name>
         <value>1</value>
     </property>
    
    • dfs.repliacation: 文件副本数量,设为集群机器数。虚拟环境 中设为1.
  5. 修改yarn-site.xml

     <property>
         <name>yarn.nodemanager.aux-services</name>
         <value>mapreduce_shuffle</value>
     </property>
    

    抄的,我也不知道具体有什么用。

  6. 复制mapred-site.xml.template,命名mapred-site.xml

     <property>
         <name>mapreduce.framework.name</name>
         <value>yarn</value>
     </property>
    
    • mapreduce.framework.name: 设置Map-Reduce框架,此处选Yarn。

2. 运行后台服务

在运行之前,确保前面设置的Hadoop文件系统对应的目录已经准备好, 并且目录是空的。然后初始化HDFS文件系统:

hdfs namenode -format

开启后台服务:

start-dfs.sh
start-yarn.sh

关闭后台服务:

stop-yarn.sh
stop-dfs.sh

后台服务启动后,可以通过http://localhost:50070监视运行状态。 同时,在命令行中可以用jps查看Hadoop服务启动是否正确。

例如,jps命令中不存在DataNode,则可能是执行

hdfs namenode -foramt

之前没有清空设定的目录。

3. 访问HDFS

常用命令:

hadoop fs -ls [<path>]
hadoop fs -mkdir <path>
hadoop fs -mv <path>
hadoop fs -rm <path>
hadoop fs -put <local-path> <hdfs-path>
hadoop fs -get <hdfs-path> <local-path>
hadoop fs -help

简单的浏览可以直接通过浏览器:

http://localhost:50070

4. 运行测试样例

假定后台服务已启动,而且已经在Hadoop的安装目录中,可以执行PI测试:

hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.5.2.jar pi 20 10

如果执行成功,最后会显示一个极其粗糙的PI值。

5. Intellij IDEA中配置依赖

  1. 创建普通Java项目

  2. 添加引用

    1. FileProject Structure...ModulesDependencies+Library...Java

    2. 选择/usr/local/Cellar/hadoop/2.5.2/libexec/share/hadoop 目录下除了httpfs外的全部文件夹。

    3. Name可以随便写,例如”common”,OK。

    4. +Jars or directories...

    5. 选择/usr/local/Cellar/hadoop/2.5.2/libexec/share/hadoop/common/lib

    此时Dependencies内应该总共增加了一个”common”和一个”lib”目录。

  3. 修改Project Structure中的Artifacts,增加Jar包的生成配置。

可以写代码编译打包了。

osx

com.android.support:appcompat错误

使用Intellij IDEA创建Android项目,编译时提示“compile ‘com.android.support:appcompat-v7:19.+’”错误, 解决方法是运行Android SDK Manager,勾选:

  • Android Support Repository

  • Android Support Library

重新打开项目编译,问题解决。

参见:http://stackoverflow.com/questions/18045712/gradle-build-android-project-could-not-resolve-all-dependencies-error-but-i-t

iOS 7越狱调试

iOS 7中苹果彻底放弃了对gdb的维护,所以必须用C/S模式来调试程序。

配置调试环境

采用的调试环境为gdb-server(iOS 7)+ lldb(OS X)。

在iOS SDK中带有debugserver,我们要做的就是把debugserver打补丁,然后复制到iOS下运行。 完整的教程参考这个链接

  1. 复制debugserver,使用lipo取出合适的部分,例如运行在armv7设备上:

     lipo -thin armv7 debugserver -output dbgserverv7
    
  2. 把以下文件保存为ent.xml,下一步ldid会用到它为文件添加权限位:

     <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
     <plist version="1.0">
     <dict>
         <key>com.apple.springboard.debugapplications</key>
         <true/>
         <key>get-task-allow</key>
         <true/>
         <key>task_for_pid-allow</key>
         <true/>
         <key>run-unsigned-code</key>
         <true/>
     </dict>
     </plist>
    
  3. 用ldid进行伪签名,ldid可以用brew安装:

     ldid -Sent.xml dbgserverv7
    
  4. 把dbgserverv7用任何办法复制到iOS设备上,准备部分就完成了。

启动调试

基本思路是在iOS下运行dbgserver,然后在OS X下运行lldb,连接至iOS。

  1. 在iOS下执行服务器端,在这里监听了端口:

     dbgserverv7 0.0.0.0:8888
    
  2. 把调试的文件从iOS复制到OS X下,以便lldb载入。当然,如果调试的自己的程序,有了符号表 就可以省略这个步骤了,lldb会自动找到源码。

  3. 在OS X下运行lldb,其实gdb也是可以的。然后在lldb中使用gdb-server命令连接调试服务器:

     lldb
     (lldb) gdb-server 192.168.1.11:8888
    

如果没有错误信息,连接就成功建立了。

LLDB技巧

初学lldb,可以参考这个文档,记载了gdb命令与lldb命令的对应:

  • 等待进程启动

      (lldb) process attach --name XXXX --waitfor
    
  • 查询符号表

      (lldb) image lookup -s NAME_TO_FIND
    
  • 反汇编函数

      (lldb) disassemble -n FUNCTION_NAME
    

可能还会陆续更新(?)

ios

由LLVM版本引发的诡异问题

LLVM提供了编译器基础设施,根据语法树可以方便的生成LLVM IR,然后编译成可执行文件。

然而在尝试创建一个函数时,发现无法获取函数参数值。代码如下:

1
2
3
4
5
6
auto t_fib = FunctionType::get(t_int, t_fibargs, false);
auto fib = Function::Create(t_fib, Function::ExternalLinkage, "func_fib", m);

auto argsfib = fib->arg_begin();
auto n = argsfib++;
n->setName("n");    // n == NULL

此段代码非常简单,首先创建一个函数原型int fib(int n),使用原型创建实例,然后在 实例中获取第一个参数n。然而执行到注释的语句时会出现空指针错误。

在此处浪费了许多时间,最终发现是由于LLVM版本错乱而引发的问题。我的开发环境是OS X、 Xcode。此前为了使用iPython安装了Anaconda,它自带了一份LLVM 3.3,并且设置了PATH 环境变量;而现在换成从Homebrew安装的LLVM 3.4.1,一切就正常了。

OpenWRT下的GDB远程调试

编写的程序部署到OpenWRT上出错,打日志是一个好办法,但是今天遇到的情况,日志也不能 显示出正确的程序流程,实在诡异,因此决定尝试调试器。

路由器中的存储空间十分有限,OpenWRT的包管理器opkg提供的GDB占用大约1.5MB空间。路由器 本身有8M的存储空间,目前只剩200KB了,GDB的大小不能接受。相比之下,GDBServer的大小 不到100KB,这是可以接受的。

下面是使用GDBServer远程调试的方法:

  • 路由器端

    1. 安装GDBServer

        opkg install gdbserver
      
    2. 进入目录,运行GDBServer,监听到网络端口

        gdbserver 192.168.8.1:4455 tubed
      
  • 计算机端

    1. 根据OpenWRT SDK的位置设置环境变量

    2. 进入被调试文件的所在目录,这是为了向GDB提供程序的调试信息

    3. 指定被调试的程序文件,启动gdb

        mips-openwrt-linux-gdb tubed
      
    4. 在GDB中连接远程调试器

        target remote 192.168.8.1:4455
      

如果连接成功,则此时就可以像平常一样使用GDB来调试程序了,不过调试目标是位于路由器的 程序。使用这个方法可以很轻易的定位到程序错误的位置。毕竟是动态调试。话说回来,既然 可以做到GDB远程调试,也许可以把部署、调试的环节通过Makefile整合到Xcode项目中来?

有空可以试一下看看。

Xcode下创建OpenWRT交叉编译项目

Xcode版本5.0.2,编译环境是OpenWRT SDK(mips-openwrt-linux-uclibc)。利用Xcoce的 “外部编译系统(External build system)”来实现在IDE中开发OpenWRT项目。

Xcode交叉编译配置

新项目和旧项目中都可以,在项目中创建目标“外部编译系统”(OS X – Other – External Build System),选择使用编译工具为“/bin/make”。

没错,需要使用Makefile系统来实现交叉编译。也许cmake也是可行的,但不做讨论。所以 后文会给出一个简单的交叉编译Makefile教程。

这么做已经足够,但是Xcode的代码补全功能只对它支持的编译目标做处理,所以还需要 一点小技巧。

修复代码补全失效

方法来自于StackOverflow上的这个页面。基本思路是,创建一个普通的“命令行” 目标(OS X – Application – Command Line Tool),名字任意,在其编译文件列表中添加 所有的代码文件。这就强制Xcode解析所有的代码文件,从而启用代码完成功能。

快,糙,猛。

如果觉得新目标生成的几个文件比较烦人,还可以删除掉编译阶段中的“复制”阶段,然后就 可以清理好项目目录了。

Makefile编写

Xcode对外部编译系统的支持,实质上是通过Makefile实现的。只要在项目目录中写好了 Makefile文件,就可以像普通项目一样使用IDE了。

所以说,可以参考任何一篇Makefile教程来编写这个文件。要实现交叉编译,就需要编写 支持自订工具链的Makefile。

下面是一个Makefile文件的模板,它会编译目录下所有的c与cpp文件。可惜的是我找不到 它的来源了,下面的是经过我修改后可以用于OpenWRT SDK工具链的版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
SDK := /Volumes/OpenWrt/trunk/staging_dir
SDKBIN := $(SDK)/toolchain-mips_34kc_gcc-4.6-linaro_uClibc-0.9.33.2/bin
export STAGING_DIR := $(SDK)
export PATH := $(SDKBIN):$(SDK)/host/bin

AR := $(SDKBIN)/mips-openwrt-linux-uclibc-ar
AS := $(SDKBIN)/mips-openwrt-linux-uclibc-as
CC := $(SDKBIN)/mips-openwrt-linux-uclibc-gcc
CXX := $(SDKBIN)/mips-openwrt-linux-uclibc-g++


program_NAME := tubed

program_C_SRCS := $(wildcard *.c)
program_CXX_SRCS := $(wildcard *.cpp)

program_C_OBJS := ${program_C_SRCS:.c=.o}
program_CXX_OBJS := ${program_CXX_SRCS:.cpp=.o}
program_OBJS := $(program_C_OBJS) $(program_CXX_OBJS)
program_INCLUDE_DIRS :=
program_LIBRARY_DIRS :=
program_LIBRARIES :=

CFLAGS += -std=$(GCC_C_LANGUAGE_STANDARD)
CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir))
LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir))
LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library))

.PHONY: all clean distclean 

all: $(program_NAME)

$(program_NAME): $(program_OBJS)
  $(LINK.cc) $(program_OBJS) -o $(program_NAME)

clean:
  @- $(RM) $(program_NAME)
  @- $(RM) $(program_OBJS)

distclean: clean

define OBJECT_DEPENDS_ON_CORRESPONDING_HEADER
  $(1) : ${1:.o=.h}
endef

  $(foreach object_file,$(program_OBJS),$(eval $(call OBJECT_DEPENDS_ON_CORRESPONDING_HEADER,$(object_file))))

至此,Xcode下的交叉编译环境已经完成。

OS X下搭建OpenWRT开发环境

本文记叙了如何在OS X环境下搭建一个OpenWRT的交叉编译开发环境。主要目的并不是为了编译OpenWRT 操作系统,而是编译一套用于开发第三方程序的SDK。本文编译的是MIPS指令集,基于uClibc的工具链, 适用于类似TP-Link 720N的路由器。

准备

  1. Homebrew或者类似的包管理器;
  2. 一套OS X的工具链,例如Xcode的命令行工具,或者是从Homebrew安装的GNU工具链;
  3. OpenWRT源代码;
  4. 10G左右的空闲硬盘空间。

编译SDK

  1. 首先需要说明的是,我只想得到一份可用的SDK,而不想要整个系统,因此依照以下步骤不见得能编译出 一份可用的系统。其次,官方编译教程在这里: http://wiki.openwrt.org/zh-cn/doc/howto/buildroot.exigence

  2. OpenWRT只支持在大小写敏感的文件系统中编译,不分区的话,可以用hdiutil工具创建一个10G左右的 dmg映像来代替: hdiutil create -type SPARSE -fs 'Case-sensitive Journaled HFS+' -size 10g openwrt.dmg 然后装载dmg文件,就可以在载入的卷宗中编译了。

  3. 先进行环境配置

     make defconfig
     make prereq
     make menuconfig
    

    执行这些命令的过程中,多半会提示缺少软件包,用Homebrew来安装,下面列举其中一部分。

    1. (软件包getopt):brew install gnu-getopt,找到可执行文件,在/usr/local/bin下制作一个符号 链接,名字为gnugetopt

    2. (软件包fileutils等):brew install coreutils

    3. (软件包awk):brew install gawk

    4. (软件包wget):brew install wget

  4. 顺利进入menuconfig,需要根据路由器选择Target System、Subtarget、Profile,确保选中OpenWrt SDK、 Toolchain。

  5. 保存退出menuconfig,执行make来编译,编译过程较长,完成后staging_dir中就是我们需要的工具链。

使用工具链

  1. 设置STAGING_DIR环境变量,指向SDK的staging_dir目录,设置PATH环境变量,在其中添加SDK 工具链的bin目录: <省略...>\staging_dir\toolchain-mips_34kc_gcc-4.6-linaro_uClibc-0.9.33\bin

  2. 准备好需要编译的源码文件,对于C程序,可以运行mips-openwrt-linux-gcc,对于C++程序, 可以运行mips-openwrt-linux-g++,来进行交叉编译。(对于其他路由器,gcc名字会有所不同)

  3. 我觉得第1步麻烦,就直接用这段脚本来代替手动修改环境变量了:

1
2
3
4
5
    #!/bin/bash

    export PATH=$PATH:`pwd`/toolchain-mips_34kc_gcc-4.6-linaro_uClibc-0.9.33.2/bin:`pwd`/host/bin
    export STAGING_DIR=`pwd`
    bash

最后用任何手段(例如scp)把编译出的程序发送到路由器,直接运行即可。如果希望制作ipkg包,可能还需要 更深入的研究OpenWrt SDK。

用Keil调试节省时间

对单片机开发还不熟练,经常会写出bug,但是PCB上面总是插拔各种线比较麻烦。这次串口协议 出了问题,发现Keil的仿真器支持模拟串口的功能,在仿真器里调试就方便多了。

打开串口面板,在内部按下的按键就会发送到单片机,不过还不知道怎么直接发送16进制数据。 此外,虽然Keil支持串口调试,但是似乎不能模拟PWM,即使有一个逻辑分析仪面板好像也没用。

OS X下的USB转串口方案

这里记载OS X下的USB-Serial转换方案。

硬件

  • 适配器

淘宝上很便宜的USB串口适配器,基于Silicon Labs的CP2012芯片,Windows、Linux和 OS X下都有驱动: http://www.silabs.com/products/mcu/pages/usbtouartbridgevcpdrivers.aspx

  • 下位机

GL-iNet路由器,硬件结构类似TP-Link 720N,但是PCB上面保留了UART引脚方便连接。 路由器规定的波特率是115200。串口通信涉及三个必要的引脚:TX、RX、GND。连接方式如下:

    适配器RX - TX路由器
    适配器TX - RX路由器
    适配器GND - GND路由器

软件&使用方法

  • screen

OS X自带的命令行工具,可以用来连接USB虚拟串口,使用方法为:

    screen /dev/cu.SLAB_USBtoUART 115200

这里的/dev/cu.SLAB_USBtoUART是虚拟串口的设备文件名,确保装好了适配器的驱动,插入适配 器应该就会找到它们了。电脑通过/dev/cu.*设备文件来连接其他串口设备,通过/dev/tty.* 接受来其他设备的连接。

似乎screen的主要作用是在单窗口环境里模拟多个终端窗口,顺带可以作为虚拟串口的连接工具。 但是在OS X的终端里使用screen工具,就不能利用终端的滚动条来查看历史记录了。我经常要去翻 看历史记录,这一点不能接受。

  • SecureCRT

这是一个价格昂贵的商业软件,据说是目前OS X下最好的串口工具。软件是全图形化的,不需要设 置就可以使用。目前对我来说,它最大的优势是可以通过滚动来查看历史记录,虽然界面水平远低 于OS X的平均水准,但用起来还是很方便的。可以从这里下载试用版: http://www.vandyke.com/products/securecrt/

Init

初始化