2014年7月28日月曜日

autoconf と automake その2

前回のautoconfとautomakeのその2です。前回よりもう少しだけ難しいことをしてみます。
  • フォルダの階層分けをする
  • GTKを使う
  • 国際化(言語によって、文字列を切り替える)を行う

まずソースコードをsrcフォルダに入れて、src/main.c, src/func.h, src/func.cのフォルダに入れます。プログラムは以前にGTK+3.0用に書いたサンプルとほぼ同じです。ENABLE_NLSの部分が国際化の部分です

src/main.c
#include "config.h"
#include "func.h"
#include <gtk/gtk.h>
#include <glib/gi18n.h>

int main(int argc, char *argv[])
{
#ifdef ENABLE_NLS
        bindtextdomain(PACKAGE, LOCALEDIR);
        bind_textdomain_codeset(PACKAGE, "UTF-8");
        textdomain(PACKAGE);
#endif
        gtk_init(&argc, &argv);
        func();
        return 0;
}


src/func.h
void func.c();


src/func.c
#include "config.h"
#include <gtk/gtk.h>
#include <glib/gi18n.h>

void func()
{
        GtkWidget *dialog;

        dialog = gtk_message_dialog_new(NULL, 
                                GTK_DIALOG_DESTROY_WITH_PARENT, 
                                GTK_MESSAGE_OTHER,
                                GTK_BUTTONS_OK,
                                _("Hello!")
                                );
        gtk_dialog_run(GTK_DIALOG(dialog));
        gtk_widget_destroy(dialog);
}

この場合、Makefile.amを直下とsrc以下に2つ作成する必要があります。

Makefile.amでは、makeを行うサブディレクトリの指定をしています。またACLOCAL_AMFLAGSはaclocalを再実行するときの m4フォルダ(後述)を指定しています。

src/Makefile.amでは、AM_CPPFLAGSで、コンパイル時に渡すオプションの指定をしています。-DLOCALEDIRは国際化のためのディレクトリの指定で、@GTK_CFLAGS@はGTKを使うためのpkg-config --cflagsと同等です。amtest_LDADDはリンクするライブラリの指定です。@GTK_LIBS@はpkg-config --libsと同等になります。

Makefile.am
ACLOCAL_AMFLAGS = -I ./m4
SUBDIRS = src po


src/Makefile.am
AM_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" @GTK_CFLAGS@
bin_PROGRAMS = amtest
amtest_SOURCES = main.c func.c func.h
amtest_LDADD = @GTK_LIBS@


configure.acは以下のように書き換えます。青色の部分が前回と違う部分です。AC_CONFIG_AUX_DIR(config)では、install-sh等のサポートスクリプトをconfigディレクトリに置くための指定です。IT_PROG_INTLTOOLからAM_GLIB_GNU_GETTEXTまでは、国際化のためです。PKG_PROG_PKG_CONFG, PKG_CHECK_MODULESはpkg-configを使用するための設定です。AC_CONFIG_FILESには、サブディレクトリのMakefileの作成を指示します。

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.68])
AC_INIT([Automake Test], 1.1, foo@example.com, amtest)
AC_CONFIG_AUX_DIR(config)
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([src/func.c])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL

# Checks for libraries.
IT_PROG_INTLTOOL
GETTEXT_PACKAGE=amtest
AC_SUBST(GETTEXT_PACKAGE)
AM_GLIB_GNU_GETTEXT
PKG_PROG_PKG_CONFIG
PKG_CHECK_MODULES(GTK, gtk+-3.0)
# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_CONFIG_FILES([Makefile
                 src/Makefile
   po/Makefile.in])
AC_OUTPUT



AM_GLIB_GNU_GETTEXT等は、これだけでは使用できません。m4フォルダにこれらを使うためのマクロを置く必要があります。以下を実行してください。これでGLIB_GNU_GETTEXTを使用するための準備となります。po/Makefile.in.inも作成されます。必要なm4ファイルが表示されるので、/usr/share/aclocal/フォルダからm4フォルダにコピーしてください(無くても良いようですが)

$ glib-gettextize -c -f

同様にして、pkg.m4, glib-gettext.m4 もコピーしてください。

また各国語用のファイルとして、po/POTFILES.inとpo/LINGUASのファイルを作成します。それぞれ、翻訳する文字列が入っているソースコードと、翻訳する言語を指定します。

po/POTFILES.in
# List of source files which contain translatable strings.
src/func.c

po/LINGUAS
ja

ただ、このままだとpo/LINGUASファイルを参照しないようなので、intltoolも入れます。これで、再度po/Makefile.in.inが書き換わります。MinGWの場合は、このサイトからintltool_0.40.4-1_win32.zipをダウンロードし、解凍したものをmsysのフォルダに上書きしました。ただし、Makefile.in.inのコピーには失敗するので、手動でコピーしています。

$ intltoolize -c -f --automake

ここまで、終われば、後はほぼ従来通りに、以下を行えば良いです。ただし、aclocale実行時には、m4フォルダを指定するようにします。

$ aclocal -I ./m4
$ automake -a -c
$ autoconfig
$ ./cofigure


日本語化に関しては、以下の作業を行います。ja.poで"Hello!"に対応する日本語を設定すれば良いです。

$ cd po
$ make amtest.pot
$ cp amest.pot ja.po
$ vi ja.po


実はMinGW環境で、poフォルダのmake update-poがエラーになる問題が残っているのですが、とりあえずはこれで説明を終わりたいと思います。

世の中には色々なOSがありますが、一つのOSだけで動くソフトウェアを作るよりも多くのOSで動くソフトウェアの方を作るほうが面白いと思っています。その中でC言語を使った場合には、Javaと違いビルドの問題があるのですが、それをautotoolsは解決する仕組みとなっています。

なお、このautotoolsについては以下の書籍を参考にさせていただきました(前回の例はそのまま)。


私の説明は簡単な物でしたが、各コマンドの役割、各ファイルの役割、configure.acでのチェックの指令方法など、更に詳しく書かれています(詳しい分、少しとっつきにくい点もありますが)。他にもLinuxでのプログラム作成に役立つことが色々と書かれており、勉強になりました。Linuxのプログラミングに興味を持つ方は読む価値があるかと思います。

2014年7月27日日曜日

autoconf と automake

autoconf と automake の説明


Linuxでソースコードをダウンロードしてビルドして使用するときには、大抵は同じ手順で行うことが出来ます。tarアーカイブ形式で配布されていて、例えばpkg.tar.gzというtarアーカイブの場合は以下のようになります。

$ tar zxvf pkg.tar.gz
$ cd pkg
$ ./configure
$ make
$ sudo make install

1行目は圧縮ファイルを解凍。
2行目は 解凍したディレクトリへ移動。
3行目は環境の調査とMakefile(ビルドのためのファイル)の作成。
4行目はソースコードのビルド
5行目はインストール

と、非常に簡単にビルドしてインストールができるようになっています。

特徴的なのが3行目でしょう。世の中にはLinux以外にも色々なOSがあります。また同じLinuxであってもPCによってインストールされたソフトウェアが違うなど環境が異なります。configureでそのOSや環境の違いを考慮することができるようになっています。

このconfigureというファイルはスクリプトファイルです。このスクリプトを作成するためのツールがautoconfです。また環境に合わせてビルドを行うためのMakefileをconfigureが書き換えますが、そのMakefileの作成を容易に作成するためのツールがautomakeです。 今回は説明しませんが、ライブラリを作成するためのLibtoolもあります。autoconfとautomakeとLibtoolを合わせてautotoolsと言います。

autoconf と automake の例


これらのautoconfとautomakeを使ったtarアーカイブの作り方の例です。例はAutomake Testという名前のアプリケーションで実行ファイル名はamtest、ファイルはmain.cとfunc.cから作成されています。エディタにはviを使うとします。コマンドの流れは以下のようになります。

$ mkdir amtest; cd amtest
$ vi main.c
$ vi func.c
$ autoscan
$ mv configure.scan configure.ac
$ vi configure.ac
$ vi Makefile.am
$ aclocal
$ autoheader
$ touch NEWS README AUTHORS ChangeLog
$ automake -a -c
$ autoconf
$ ./configure; make
$ make dist


これで、amtest-1.0.tar.gzの作成が出来ます。



1つ目はamtestのディレクトリを作成し、そのディレクトリに移動します。
2つ目はmain.cを作成します。例なので、以下のような簡単なものです。

#include "config.h"

void func();

int main()
{
        func();
        return 0;
}

3つ目はfunc.cを作成します。同じく例で、以下のようなものです。PACKAGE_STRINGは自動的に作成されるconfig.h内に記述されます。

#include "config.h"
#include <stdio.h>

void func()
{
        puts(PACKAGE_STRING);
}

4つ目は、autoscanで自動的にソースコードを検証し、configureの元となるconfigure.scanを作成します。

5つ目ではconfigure.scanをconfigure.acに名前を変更します。autoscanはもしソースコードに大きな修正があった場合には実行し、configure.scanへの差異をconfigure.acに反映することになります。

6つ目ではconfigure.acの中身を書き換えます。変更点は青色の部分です。configure.acの5行目はソフト名、バージョン名、連絡先、パッケージ名の設定で、6行目はautomakeの使用を設定、12行目はインストールスクリプトのチェックの設定、22行目はMakefileを作成することを指定します。

本来なら、ここで他にもヘッダーファイルの存在確認などチェックしたい内容を書き足す必要があります。

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.68])
AC_INIT([Automake Test], 1.0, foo@example.com, amtest)
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([func.c])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_CONFIG_FILES([Makefile])
AC_OUTPUT

7つ目ではMakefile.inの元となるMakefile.amを作成します。bin_PROGRAMSで実行ファイル名をamtest_SOURCESで全てのソース(ヘッダーを含む)を指定します。

bin_PROGRAMS = amtest
amtest_SOURCES = main.c func.c


8つ目のaclocalでは、autoconfでautomakeを使用するためのマクロであるaclocal.m4を自動作成しています。

9つ目のautohedaderではconfig.hの元となるconfig.h.inを自動作成しています。

10つ目では、automakeで必要となるファイル(NEWS, README, AUTHORS, ChangeLog)をとりあえず空(ゼロバイト)のファイルとして、作成しています。

11個目のautomakeで、Makefile.inが作成されます。-a -c はinstall-sh, missing, depcomp 等のサポートスクリプトを自動作成するためのオプションです。

12個目のautoconfで、configureスクリプトを作成し、これでビルドの準備は完了です。

13個目は正しくプログラムが出来たことを確認するビルド作業です。configureスクリプトを実行すると、Makefile.inとconfig.h.inから、Makefileとconfig.hを作成します。そしてmakeを実行すると実行ファイルのamtestが作成されます。

14個目のmake distで、amtest-1.0.tar.gzが作成されます。ビルドで作成されたMakefile等は含まれず、必要なファイルのみ含まれるようになっています。

tarアーカイブの作成例の説明は以上です。 もちろんFedora 20でもWindows上のMinGWでも同様です。

2014年7月20日日曜日

Chromeの不具合?とWindowsの仕組み

最近、Google ChromeがノートPCのバッテリを過剰消費しているという不具合が話題に上がっていました。

これはFirefoxやInternet Explorerでは起きない不具合となっているのですが、Windowsの仕組みの問題でもあるので、改善されるに越したことはないですが、Chromeを責めるのも少し可哀想な気がします。

OSの仕組み


WindowsなどのOSでは、起動している状態でもかなり多数のアプリケーション(プロセス)が起動しています。それに比べてCPUは多くても8つなど数が少なく、1つの場合もあります。よって、少ないCPUで複数のアプリケーションを切り替えながら実行する必要があります。

OSの中でその切り替えの役割を担っているプログラムをスケジューラと言います。このスケジューラは定期的に実行され、どのアプリケーションがCPUを必要としているかを判断し、実行するアプリケーションをCPUに割り当てます。

このスケジューラを定期的に実行する間隔が、記事に書かれている「システムティックレート」と言われているもので、割り込みコントローラと言うものが、CPUに定期的に実行するように指令しています。

Windowsの場合


Windowsの場合はスケジューラの実行間隔が15msと言うことです。ちなみに最近はあまり見かけないですが、1CPUのパソコンの場合には10msとなっています。

この15msと言う数字は一秒間に約67回スケジューラが動いていると言うことになり、人間から見ると、アプリケーションの切り替えが分からず、同時に複数のアプリケーションが動いているようにみえるわけです。

しかし、15msが速いかというと、コンピュータの世界では非常に遅く(例えば、CPUの1命令が1クロックで行われるとすると、1GHzのCPUでも1命令は0.000001msで完了する)、処理によっては、この間隔で切り替えられても困ることになります。特に動画や音楽関連などリアルタイムな処理をしたい場合は致命的です。

そこで、WindowsではtimeBeginPeriod()というマルチメディア用Win32APIによって「システムティックレート」を切り替えできるようになっています。以下のソースコードのように使い方は非常に簡単です(ビルド時にはwinmm.libをリンクしてください) 。


#include <windows.h>
#include <mmsystem.h>

int WINAPI WinMain(HINSTANCE hInstance,
                HINSTANCE hPrevInstance,
                LPSTR lpCmdLine,
                int nCmdShow)
{
        timeBeginPeriod(1);
        MessageBox(0, "ok end", "sysmtem tick test", MB_OK);
        return 0;
}


ダイアログが表示されますが、ここでOKを押してこのアプリケーションが終了するまで、「システムティックレート」が1msとなります。ちなみにWindows上に動いているアプリケーションの中でtimeBeginPeriod()に指定した値が一番低い値がシステムで使われることになります。

そして、以下のプログラムを上記のプログラムが実行している状態と実行していない状態で動作させてみてください。

#include <windows.h>

int main()
{
        int i;
        for (i = 0; i < 1000; i++) {
                Sleep(1);
        }
        return 0;
}


timeBeginPeriod(1)を実行している状態だと終了が速いはずです。Sleep(1)は少なくとも1msは別のアプリケーション(プロセス)の処理を行ってください、という指令です。しかし「システムティックレート」切り替え間隔が15msの場合には、アプリケーションの切り替えに15msかかってしまうためにSleep(1)は少なくとも15msの時間がかかるためです。

そしてあるCPUでSleep()指令を実行した後に、15ms経って他のアプリケーション切り替えするまでの間はというとCPUはどのアプリケーションも実行していない状態になり、非常に無駄な時間を使うことになります。

そのため頻繁なプロセスの切り替えを行うとパフォーマンスが大幅低下します。Google Chromeは昔から処理が速いことで評判でしたが、 単に消費電力よりパフォーマンスを取った結果と思っていました。

Internet Explorerはバージョン10の時に、消費電力が他のブラウザよりも低いとMicrosoftは宣伝していました。
この頃からChromeはtimeBeginPeriod(1)を使用しているはずですけど、それほどの差はありません。なぜ今ごろまた騒がれているのかが不思議です。もしかすると最近のCPUは省電力機能が発達してきているので、15msの間に積極的に休むようになってきたのかもしれません。

しかし、1つのアプリケーションの timeBeginPeriod(1)の1つの命令でシステム全体に影響を与えるWindowsの仕組みも少々怖い気がします。少なくとも短い間隔のSleep()でタイミングを合わすようなプログラムは書かない方がいいでしょう。

Linuxの場合


Linuxの場合は、tickless(ティックがない)と呼ばれる仕組みが2.6.21から使われています。Windowsのように15msというような一定の期間を設けず、動的に変更するようになっているので、dynaticks(dynamic ticks) (動的なティック)と呼ばれることもあります。

その動的な値を知るためにはPowerTopというソフトで得られます(sudo yum install powertop でインストール)。Fedora 20で確認したところ、色々な普通に使っている状態で一秒間に約800の割り込みが起きています。これを計算すると1.4msぐらいのティックになるので、Linuxは結構消費電力を使っているということになってしまうかもしれません。LinuxではChromeの不具合は起きないと言っても、消費電力を使うのであれば意味がない気がします。ただChrome自体の割り込みは全部合わせても100回/秒程度のようです。

それと、Fedora20ではLinux3.10から導入された完全なticklessであるFull ticklessが使用されていません。確認するには/boot/config-3.13-3-201.fc20.x86_64などのconfigファイルを見ると分かりますが、CONFIG_NO_HZ_FULLが設定されていません。これが使用されると更に消費電力がよくなるかもしれませんが、このティックの辺りはOSの基本の部分であり、少しでも割り込みを減らすのには課題が多そうです。

Mac OS Xも資料が少ないので詳細は判りませんが、ticklessのようです。

2014年7月14日月曜日

Androidでアプリのバックアップ/復元

以前にFedora 19でのNexus 5のroot化のブログを書きましたが、なぜroot化をするかを書いていませんでした。

Androidをroot化する理由は、Titanium Backupというアプリを使うためと言っても良いかもしれません。

Androidは、端末をリセットした際などに再度同じGoogleアカウントを設定すると、以前の同じユーザーのアプリを入れなおして、ある程度前と同じ環境に復元してくれます。

しかし、設定した内容や保存した内容が忘れられてしまうアプリがほとんどです。この点だけでもなんとかなってくれるとAndroidも更によくなると思うのですけど・・・。

そこで、 Titanium Backupというアプリを利用すると、設定した内容や保存した内容のバックアップと復元が可能になります。

Titanium Backupには有料版と無料版がありますが、無料版はアプリを一つずつしかバックアップできず、不便な点があります。バックアップするアプリが多い人は有料版を使用した方がいいでしょう。

無料版の使い方は簡単です。「バックアップ/復元」を選択するとアプリのリストが出てきます。 


ここでバックアップや復元をしたいアプリを選択すると、以下のような表示がでるので、
バックアップまたは復元を行ってください。


PCに接続すると内部ストレージ直下にTitaniumBackupというフォルダがありますので、OSの入れ替えを行うなどリセットする際にはPCにバックアップをとっておき、復元するときには、元の位置に戻せば良いです。