gdbでgetopt()のoptind/optoptを参照したときに値が違うように見える

結構ハマったのでメモ。

#include <stdio.h>
#include <getopt.h>

char *short_opts = "ab:";
struct option long_opts[] = {
	{"test", no_argument, 0, 0},
	{"add", required_argument, 0, 0},
	{0, 0, 0, 0}
}; 
int main(int argc, char *argv[]) {
	int c = 0;
	int longindex;

	while (1) {
		longindex = 0;
		c = getopt_long(argc, argv, short_opts, long_opts, &longindex);
		if (c == -1) {
			break;
		}

		fprintf(stdout, "%d(%x) %d(%x) %c(%x)\n",
				c, &c, optind, &optind, optopt, &optopt);
	}
	return 0;
}

というソースがあり、getoptのextern変数optind, optoptの実際の値とgdbで参照した値が違うのに気がついた。

$ cc -g getopt.c
$ ./a.out -a -b a --test --add A
97(4cc7b7ac) 2(600ae4) (600ae0)
98(4cc7b7ac) 4(600ae4) (600ae0)
0(4cc7b7ac) 5(600ae4) (600ae0)
0(4cc7b7ac) 7(600ae4) (600ae0)
$ gdb a.out
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6_4.1)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/kohchi/C/a.out...done.
(gdb) b main
Breakpoint 1 at 0x4005e4: file getopt.c, line 14.
(gdb) run -a -b a --test --add A
Starting program: /home/kohchi/C/a.out -a -b a --test --add A

Breakpoint 1, main (argc=7, argv=0x7fffffffe1c8) at getopt.c:14
14		int c = 0;
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.132.el6_5.2.x86_64
(gdb) n
18			longindex = 0;
(gdb) 
19			c = getopt_long(argc, argv, short_opts, long_opts, &longindex);
(gdb) 
20			if (c == -1) {
(gdb) 
24			fprintf(stdout, "%d(%x) %d(%x) %c(%x)\n",
(gdb) p c
$1 = 97
(gdb) p optind
$2 = 1
(gdb) p optopt
$3 = 63
(gdb) n
97(ffffe0cc) 2(600ae4) (600ae0)    ※あれ?optind=2 optopt=0になっている。
26		}
(gdb) 

で以下のページを参照したところ、シェアードライブラリの値と実行バイナリで使っているものが2つあるらしい。
コマンドを実行すると当然シェアードライブラリ中の値となるのだが、gdbで何も指定しないと実行バイナリのものを表示するらしい。

http://www.linuxquestions.org/questions/programming-9/gdb-does-not-print-right-value-908538/

なのでgdbでは以下のように"@@GLIBC_X.X.X"を指定するとシェアードライブラリの値を参照できるようだ。

$ gdb a.out
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6_4.1)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/kohchi/C/a.out...done.
(gdb) b main
Breakpoint 1 at 0x4005e4: file getopt.c, line 14.
(gdb) run -a -b a --test --add A
Starting program: /home/kohchi/C/a.out -a -b a --test --add A

Breakpoint 1, main (argc=7, argv=0x7fffffffe1c8) at getopt.c:14
14		int c = 0;
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.132.el6_5.2.x86_64
(gdb) n
18			longindex = 0;
(gdb) 
19			c = getopt_long(argc, argv, short_opts, long_opts, &longindex);
(gdb) 
20			if (c == -1) {
(gdb) p c
$1 = 97
(gdb) p /c c
$2 = 97 'a'
(gdb) n
24			fprintf(stdout, "%d(%x) %d(%x) %c(%x)\n",
(gdb) l
19			c = getopt_long(argc, argv, short_opts, long_opts, &longindex);
20			if (c == -1) {
21				break;
22			}
23	
24			fprintf(stdout, "%d(%x) %d(%x) %c(%x)\n",
25					c, &c, optind, &optind, optopt, &optopt);
26		}
27		return 0;
28	}
(gdb) n
97(ffffe0cc) 2(600ae4) (600ae0)
26		}
(gdb) p optind
$3 = 12になっていないぞ
(gdb) p &optind
$4 = (int *) 0x38bfd8e114   ※参照先も違う
(gdb) p optopt
$5 = 630になっていないぞ
(gdb) p &optopt
$6 = (int *) 0x38bfd8e11c   ※参照先も違う
(gdb) p optind[tabを2回押す]
optind               optind@@GLIBC_2.2.5  
(gdb) p 'optind@@GLIBC_2.2.5' 
$7 = 2                                            ※OK!
(gdb) p &'optind@@GLIBC_2.2.5' 
$8 = (<data variable, no debug info> *) 0x600ae4  ※OK!
(gdb) p optopt[tabを2回押す]
optopt               optopt@@GLIBC_2.2.5  
(gdb) p 'optopt@@GLIBC_2.2.5' 
$9 = 0                                            ※OK!
(gdb) p &'optopt@@GLIBC_2.2.5' 
$10 = (<data variable, no debug info> *) 0x600ae0 ※OK!
(gdb) info var optind
All variables matching regular expression "optind":

Non-debugging symbols:
0x0000000000600ae4  optind@@GLIBC_2.2.5
(gdb) info var optopt
All variables matching regular expression "optopt":

Non-debugging symbols:
0x0000000000600ae0  optopt@@GLIBC_2.2.5
(gdb) n
18			longindex = 0;
(gdb) quit
A debugging session is active.

	Inferior 1 [process 8020] will be killed.

Quit anyway? (y or n) y
$

optindやoptoptの値で分岐していたりして、gdbデバッグしたら確実にハマるよね。

MacPortsのselfupdateがエラーになる件(MacOS X 10.7.5 Lion)

MacPortsを久しぶりに動かそうとしたら古いって言われたのでupdateしようとした。がエラー。

$ sudo port install xz
Password:
Warning: port definitions are more than two weeks old, consider using selfupdate
Error: Insufficient privileges to write to MacPorts install prefix.
$ sudo port selfupdate
Password:
--->  Updating MacPorts base sources using rsync
MacPorts base version 2.1.3 installed,
MacPorts base version 2.3.3 downloaded.
--->  Updating the ports tree
--->  MacPorts base is outdated, installing new version 2.3.3
Installing new MacPorts release in /opt/local as root:admin; permissions 0755; Tcl-Package in /Library/Tcl

Error: /opt/local/bin/port: port selfupdate failed: Error installing new MacPorts base: command execution failed
$

こちらのサイトによると、Xcodeコマンドラインツールが必要とのことで実行してみたが、--installなんてオプションがないのでインストールできない。

$ sudo xcode-select --install
Usage: xcode-select -print-path
   or: xcode-select -switch <xcode_folder_path>
   or: xcode-select -version
Arguments:
   -print-path                     Prints the path of the current Xcode folder
   -switch <xcode_folder_path>     Sets the path for the current Xcode folder
   -version                        Prints xcode-select version information
$ xcode-select -version
xcode-select version 2308.
$

どうもこのバージョンには--installなんてオプションがないらしい(OSが古いから?)。

Xcodeを起動し[Xcode] -> [Open Developer Tool] -> [More Developer Tools…] を開いてDeveloperネットワークに接続して

Commonad Line Tools(OS X Lion) for Xcode - April 2013

をダウンロード。ちなみにXcode自体は4.6.2になっている。なのでコマンドラインツールをインストールしてなかったということ。
ダウンロードしたファイル

xcode462_cltools_10_76938260a.dmg

をクリックしてマウントし、表示された

Command Line Tools(Lion).mpkg

を起動してインストールする。インストール画面に「インストールが完了しました。」が出たら終了。

その後、selfupdateしてみた。ちなみにxcode-selectがバージョンアップされるわけではない。

$ xcode-select -version
xcode-select version 2308.
$ sudo port selfupdate
Password:
--->  Updating MacPorts base sources using rsync
MacPorts base version 2.1.3 installed,
MacPorts base version 2.3.3 downloaded.
--->  Updating the ports tree
--->  MacPorts base is outdated, installing new version 2.3.3
Installing new MacPorts release in /opt/local as root:admin; permissions 0755; Tcl-Package in /Library/Tcl


The ports tree has been updated. To upgrade your installed ports, you should run
  port upgrade outdated

メッセージのとおり、ついでに portでインストールしたものもupgradeを実行した。

$ sudo port upgrade outdated
Password:
……
$

でインストールしたかったxzなんだけど、upgradeしたら入っていたみたい。

$ which xz
/opt/local/bin/xz
$ ls -l /opt/local/bin/xz
-rwxr-xr-x  1 root  admin  75384  3  9 16:41 /opt/local/bin/xz
$ which unxz
/opt/local/bin/unxz
$ ls -l /opt/local/bin/unxz
lrwxr-xr-x  1 root  admin  2  3  9 16:41 /opt/local/bin/unxz -> xz
$

結局は、OSが古い(といってももうバージョンアップできないから仕方ない)のでMacPortsのアップデートに必要なXcodeコマンドラインツールxcode-select --installでインストールできずにハマったというオチ。

参考サイトは以下。

http://t-horikiri.hatenablog.jp/entry/20131031/1383202003
http://little-braver.com/450/

MacOSXのarp-scan

以下のサイトで紹介されていたarp-scanをMacOSXにインストールして使ってみる。

http://orebibou.com/2015/04/lan%E5%86%85%E3%81%A7%E5%88%A9%E7%94%A8%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8Bip%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%82%92%E8%AA%BF%E3%81%B9%E3%82%8B%E3%80%8Earp-scan%E3%80%8F%E3%82%B3/

MacOSXのパッケージはrudixってところで作ってくれている。rudix自体をインストールしておけばコマンドでもインストールできそう。今回は以下のページからインストールするOSのバージョンのpkgをダウンロードしてインストールした。

http://rudix.org/packages/arp-scan.html

使い方

こんな感じ。

$ sudo arp-scan -I en1 -l
Password:
Interface: en1, datalink type: EN10MB (Ethernet)
Starting arp-scan 1.8 with 256 hosts (http://www.nta-monitor.com/tools/arp-scan/)
192.168.10.1	XX:XX:XX:XX:XX:XX	(Unknown)

nginxとjettyの連携

jettyはpure javaのWebサーバ、サーブレット。spdyやwebsocketも対応。nginxからtomcatという連携もあるが、ならapache使えよと思わなくもないのでjettyにしてみた。

jetty

http://download.eclipse.org/jetty/ からリリース版をダウンロードしてインストール。

$ wget http://download.eclipse.org/jetty/9.2.9.v20150224/dist/jetty-distribution-9.2.9.v20150224.tar.gz
--2015-03-27 08:38:23--  http://download.eclipse.org/jetty/9.2.9.v20150224/dist/jetty-distribution-9.2.9.v20150224.tar.gz
download.eclipse.org をDNSに問いあわせています... 198.41.30.199
download.eclipse.org|198.41.30.199|:80 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 13471366 (13M) [application/x-gzip]
`jetty-distribution-9.2.9.v20150224.tar.gz' に保存中

100%[======================================>] 13,471,366  1.64M/s 時間 15s     

2015-03-27 08:38:38 (902 KB/s) - `jetty-distribution-9.2.9.v20150224.tar.gz' へ保存完了 [13471366/13471366]

$ zcat ../jetty-distribution-9.2.9.v20150224.tar.gz | tar xvf -
$ mv jetty-distribution-9.2.9.v20150224/ dist
$ cd dist
$ cd demo-base
$ ls
etc  lib  resources  start.d  start.ini  webapps
[kohchi@localhost demo-base]$ java -jar ../start.jar
Exception in thread "main" java.lang.UnsupportedClassVersionError: org/eclipse/jetty/start/Main : Unsupported major.minor version 51.0
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:643)
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
	at java.net.URLClassLoader.defineClass(URLClassLoader.java:277)
	at java.net.URLClassLoader.access$000(URLClassLoader.java:73)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:212)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:323)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:268)
Could not find the main class: org.eclipse.jetty.start.Main. Program will exit.
$

とエラーがでる。javaのバージョンがまずい。

$ cat /etc/redhat-release 
CentOS release 6.5 (Final)
$ rpm -qa |grep jdk
java-1.6.0-openjdk-javadoc-1.6.0.0-5.1.13.3.el6_5.x86_64
java-1.6.0-openjdk-1.6.0.0-5.1.13.3.el6_5.x86_64
java-1.6.0-openjdk-devel-1.6.0.0-5.1.13.3.el6_5.x86_64
[kohchi@localhost demo-base]$ java -version
java version "1.6.0_30"
OpenJDK Runtime Environment (IcedTea6 1.13.3) (rhel-5.1.13.3.el6_5-x86_64)
OpenJDK 64-Bit Server VM (build 23.25-b01, mixed mode)
$

なのでyumでアップデートしてみた。

$ yum search openjdk
Loaded plugins: fastestmirror, refresh-packagekit, security
Determining fastest mirrors
 * base: ftp.jaist.ac.jp
 * extras: ftp.jaist.ac.jp
 * updates: ftp.jaist.ac.jp
============================= N/S Matched: openjdk =============================
java-1.6.0-openjdk.x86_64 : OpenJDK Runtime Environment
java-1.6.0-openjdk-demo.x86_64 : OpenJDK Demos
java-1.6.0-openjdk-devel.x86_64 : OpenJDK Development Environment
java-1.6.0-openjdk-javadoc.x86_64 : OpenJDK API Documentation
java-1.6.0-openjdk-src.x86_64 : OpenJDK Source Bundle
java-1.7.0-openjdk.x86_64 : OpenJDK Runtime Environment
java-1.7.0-openjdk-demo.x86_64 : OpenJDK Demos
java-1.7.0-openjdk-devel.x86_64 : OpenJDK Development Environment
java-1.7.0-openjdk-javadoc.noarch : OpenJDK API Documentation
java-1.7.0-openjdk-src.x86_64 : OpenJDK Source Bundle
java-1.8.0-openjdk.x86_64 : OpenJDK Runtime Environment
java-1.8.0-openjdk-demo.x86_64 : OpenJDK Demos
java-1.8.0-openjdk-devel.x86_64 : OpenJDK Development Environment
java-1.8.0-openjdk-headless.x86_64 : OpenJDK Runtime Environment
java-1.8.0-openjdk-javadoc.noarch : OpenJDK API Documentation
java-1.8.0-openjdk-src.x86_64 : OpenJDK Source Bundle
icedtea-web.x86_64 : Additional Java components for OpenJDK - Java browser
                   : plug-in and Web Start implementation

  Name and summary matches only, use "search all" for everything.
$ su
#
# yum install java-1.7.0-openjdk
Loaded plugins: fastestmirror, refresh-packagekit, security
Loading mirror speeds from cached hostfile
 * base: ftp.jaist.ac.jp
 * extras: ftp.jaist.ac.jp
 * updates: ftp.jaist.ac.jp
Setting up Install Process
Resolving Dependencies
--> Running transaction check
---> Package java-1.7.0-openjdk.x86_64 1:1.7.0.75-2.5.4.0.el6_6 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

================================================================================
 Package               Arch      Version                       Repository  Size
================================================================================
Installing:
 java-1.7.0-openjdk    x86_64    1:1.7.0.75-2.5.4.0.el6_6      updates     26 M

Transaction Summary
================================================================================
Install       1 Package(s)

Total download size: 26 M
Installed size: 91 M
Is this ok [y/N]: y
Downloading Packages:
java-1.7.0-openjdk-1.7.0.75-2.5.4.0.el6_6.x86_64.rpm     |  26 MB     00:07     
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
  Installing : 1:java-1.7.0-openjdk-1.7.0.75-2.5.4.0.el6_6.x86_64           1/1 
  Verifying  : 1:java-1.7.0-openjdk-1.7.0.75-2.5.4.0.el6_6.x86_64           1/1 

Installed:
  java-1.7.0-openjdk.x86_64 1:1.7.0.75-2.5.4.0.el6_6                            

Complete!
# yum install java-1.7.0-openjdk-devel
Loaded plugins: fastestmirror, refresh-packagekit, security
Loading mirror speeds from cached hostfile
 * base: ftp.jaist.ac.jp
 * extras: ftp.jaist.ac.jp
 * updates: ftp.jaist.ac.jp
Setting up Install Process
Resolving Dependencies
--> Running transaction check
---> Package java-1.7.0-openjdk-devel.x86_64 1:1.7.0.75-2.5.4.0.el6_6 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

================================================================================
 Package                    Arch     Version                    Repository
                                                                           Size
================================================================================
Installing:
 java-1.7.0-openjdk-devel   x86_64   1:1.7.0.75-2.5.4.0.el6_6   updates   9.4 M

Transaction Summary
================================================================================
Install       1 Package(s)

Total download size: 9.4 M
Installed size: 36 M
Is this ok [y/N]: y
Downloading Packages:
java-1.7.0-openjdk-devel-1.7.0.75-2.5.4.0.el6_6.x86_64.r | 9.4 MB     00:03     
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
  Installing : 1:java-1.7.0-openjdk-devel-1.7.0.75-2.5.4.0.el6_6.x86_64     1/1 
  Verifying  : 1:java-1.7.0-openjdk-devel-1.7.0.75-2.5.4.0.el6_6.x86_64     1/1 

Installed:
  java-1.7.0-openjdk-devel.x86_64 1:1.7.0.75-2.5.4.0.el6_6                      

Complete!
# yum install java-1.7.0-openjdk-javadoc
Loaded plugins: fastestmirror, refresh-packagekit, security
Loading mirror speeds from cached hostfile
 * base: ftp.jaist.ac.jp
 * extras: ftp.jaist.ac.jp
 * updates: ftp.jaist.ac.jp
Setting up Install Process
Resolving Dependencies
--> Running transaction check
---> Package java-1.7.0-openjdk-javadoc.noarch 1:1.7.0.75-2.5.4.0.el6_6 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

================================================================================
 Package                     Arch    Version                     Repository
                                                                           Size
================================================================================
Installing:
 java-1.7.0-openjdk-javadoc  noarch  1:1.7.0.75-2.5.4.0.el6_6    updates   16 M

Transaction Summary
================================================================================
Install       1 Package(s)

Total download size: 16 M
Installed size: 232 M
Is this ok [y/N]: y
Downloading Packages:
java-1.7.0-openjdk-javadoc-1.7.0.75-2.5.4.0.el6_6.noarch |  16 MB     00:10     
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
  Installing : 1:java-1.7.0-openjdk-javadoc-1.7.0.75-2.5.4.0.el6_6.noarch   1/1 
  Verifying  : 1:java-1.7.0-openjdk-javadoc-1.7.0.75-2.5.4.0.el6_6.noarch   1/1 

Installed:
  java-1.7.0-openjdk-javadoc.noarch 1:1.7.0.75-2.5.4.0.el6_6                    

Complete!
[root@localhost demo-base]# rpm -qa | grep jdk
java-1.6.0-openjdk-javadoc-1.6.0.0-5.1.13.3.el6_5.x86_64
java-1.7.0-openjdk-javadoc-1.7.0.75-2.5.4.0.el6_6.noarch
java-1.6.0-openjdk-1.6.0.0-5.1.13.3.el6_5.x86_64
java-1.6.0-openjdk-devel-1.6.0.0-5.1.13.3.el6_5.x86_64
java-1.7.0-openjdk-devel-1.7.0.75-2.5.4.0.el6_6.x86_64
java-1.7.0-openjdk-1.7.0.75-2.5.4.0.el6_6.x86_64
[root@localhost demo-base]# java -version
java version "1.7.0_75"
OpenJDK Runtime Environment (rhel-2.5.4.0.el6_6-x86_64 u75-b13)
OpenJDK 64-Bit Server VM (build 24.75-b04, mixed mode)
# 

再度、起動してみる。

# java -jar ../start.jar
2015-03-27 08:59:05.829:INFO::main: Logging initialized @862ms
2015-03-27 08:59:06.248:WARN::main: demo test-realm is deployed. DO NOT USE IN PRODUCTION!
2015-03-27 08:59:06.250:INFO:oejs.Server:main: jetty-9.2.9.v20150224
2015-03-27 08:59:06.268:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:/home/foo/jetty/dist/demo-base/webapps/] at interval 1
....

http://localhost:8080 で接続できた。
なお、jettyを起動時に動作させるには、dist/bin/jetty.sh を /etc/init.d 配下にコピーする。このスクリプトには必要な環境変数設定(JETTY_HOME)などの説明が書いてあるのでそれを参考に設定する。

nginxをつかってリダイレクト

80から8080にリダイレクトさせる設定を行う。

# cd /etc/nginx/conf.d
# cat jetty.conf 
#
# Redirecting to jetty servlect
#
server {

    listen       80;
    server_name  _;

    access_log  /var/log/nginx/jetty.access.log  main;

    location /jetty/ {
	proxy_http_version 1.1;
	proxy_pass http://localhost:8080/;
	proxy_redirect http://localhost:8080/ /;
	proxy_cookie_path /jetty /;
    }
}
# /etc/init.d/nginx start

http://localhost/jetty/ これで接続可能。

google codeが終了するらしい

Google Code shutting down」というメールが来た。

Hello,

Earlier today, Google announced we will be turning down Google Code Project Hosting. The service started in 2006 with the goal of providing a scalable and reliable way of hosting open source projects. Since that time, millions of people have contributed to open source projects hosted on the site.

But a lot has changed since 2006. In the past nine years, many other options for hosting open source projects have popped up, along with vibrant communities of developers. It’s time to recognize that Google Code’s mission to provide open source projects a home has been accomplished by others, such as GitHub and Bitbucket.

We will be shutting down Google Code over the coming months. Starting today, the site will no longer accept new projects, but will remain functionally unchanged until August 2015. After that, project data will be read-only. Early next year, the site will shut down, but project data will be available for download in an archive format.

....

意訳:
本日、googlegoogle codeプロジェクトホスティングを止めるとアナウンスした。このサービスはスケーラビリティと信頼のあるオープンソースプロジェクトを提供する目的として2006年からスタートした。これまで数百万の人々がこのサイトで提供したオープンソースプロジェクトに貢献してきた。
しかし2006年から多くのことが変化した。9年過ぎ、オープンソースプロジェクトを提供するための他の多くのものが開発者の活発なコミュニティとともに立ち上がっている。オープンソースプロジェクトを提供するためのgoogle codeミッションはGitHubやBitbucketのようなほかのものによって完成されていると認める時だ。
次月以降google codeを停止する予定である。本日からgoogle codeではもはや新しいプロジェクトを受け付けない。しかし2015年8月までは機能的には無変更のままの予定だ。その後プロジェクトのデータは読み取り専用となり、次年早々からサイトを停止する予定である。しかしプロジェクトデータはアーカイブでダウンロードが可能な予定である。

ということで終了するらしい。登録していたものはgoogle code exporterを使えばgithubに移行ができるのでgithubにアカウントがある人はすぐ移行できる。

なんだか寂しいがIT業界としては仕方ないか。

(GNU)Makefileの変数とマクロの置換

変数とマクロ置換をうまく使えば冗長なコードをまとめられるみたいだ(GNU Makefile)。

Makefile
|
+--> A/Makefile
|
+--> B/Makefile
|
+--> C/Makefile

このようにトップディレクトリにMakefileがあり、配下のA,B,CディレクトリのMakefileがある場合、なにも考えないと、

#
# Makefile
#
install:
	@make -C A install
	@make -C B install
	@make -C C install

と書いてしまう(この程度ならこれでもいいけど)が、以下のように書ける。

$ pwd
/home/foo/test
$ cat Makefile
#
# sample Makefile
# $Id$
NAMES=A B C

install: $(NAMES:%=install-%)

$(NAMES:%=install-%):
	@make -C $(@:install-%=%) install
$ cat A/Makefile
#
# sample Makefile in A directory
# $Id$
install:
	@echo "install of A directory."
$ cat B/Makefile 
#
# sample Makefile in B directory
# $Id$
install:
	@echo "install of B directory."
$ cat C/Makefile
#
# sample Makefile in C directory
# $Id$
install:
	@echo "install of C directory."
$ make install
make[1]: ディレクトリ `/home/foo/test/A' に入ります
install of A directory.
make[1]: ディレクトリ `/home/foo/test/A' から出ます
make[1]: ディレクトリ `/home/foo/test/B' に入ります
install of B directory.
make[1]: ディレクトリ `/home/foo/test/B' から出ます
make[1]: ディレクトリ `/home/foo/test/C' に入ります
install of C directory.
make[1]: ディレクトリ `/home/foo/test/C' から出ます
$ 

ちなみにカレントディレクトリのMakefile中の変数はマクロ置換により次のように展開しているはず。

install: install-A install-B install-C

install-A:
	@make -C A install
install-B:
	@make -C B install
install-C:
	@make -C C install

ここの例ではディレクトリが3つだけなのであまり有り難みを感じないが、ディレクトリが多ければ多いほど有り難い。

pgrepの-xオプション指定時はコマンド名が15文字以内でないと検索できない件

pgrepの正規表現オプション"-x"であるが、これを指定するとコマンド名が15文字である必要がある。
pgrep -x とすると ^(コマンド名)$ (regcomp()に渡す文字列なのでおそらく文字列中の括弧は正規表現のグルーピングでなく純粋に"(",")"という文字として扱うはず)という正規表現となるようだ(pgrep.c)。

$ which pgrep
/usr/bin/pgrep
$ rpm -qf /usr/bin/pgrep
procps-3.2.8-25.el6.x86_64
$ wget ftp://rpmfind.net/linux/sourceforge/f/fu/fuduntu/sources/procps-3.2.8-15.fc14.src.rpm
$ mkdir procps
$ cd procps
$ rpm2 cpio ../procps-3.2.8-15.fc14.src.rpm | cpio -i
$ zcat procps-3.2.8.tar.gz | tar xvof -
$ cd procps-3.2.8
$ vi pgrep.c

do_regcomp()401行付近
            sprintf (re, "^(%s)$", opt_pattern);

正規表現の検索対象はどうも、/proc/プロセスID/statというファイルの第二フィールドのようで、そこに先頭15文字までしか書かれていないためだと思われる。