Hatena::Groupcprogramming

Going My C Way このページをアンテナに追加 RSSフィード

2010年10月24日(日)

Makefile の変更

| 09:09 |  Makefile の変更 - Going My C Way を含むブックマーク はてなブックマーク -  Makefile の変更 - Going My C Way  Makefile の変更 - Going My C Way のブックマークコメント

C 標準ライブラリ関数を書いてみるのに使っている Makefile を変更します。

dump() を含む libtestmisc.a をリンクするためです。

また、コンパイルオプションに -g (デバッガでソース追跡できるように)を追加します。

DEBUG    = -DTEST_MAIN -g
#STANDARD = -std=c89
STANDARD = -std=c99
CFLAGS   = ${DEBUG} -Wall -Wextra ${STANDARD} -L.
LDLIBS   = -ltestmisc

.PHONY : all

# (注意!) コマンド行 (-@echo のところ)は行頭が *タブ* です.
all :
    -@echo "usage: make target"

libtestmisc.a と testmisc.h は カレントディレクトリにあることを想定しています。

今後はこの Makefile を使っていきます。

テスト用の雑関数 dump()

| 08:40 |  テスト用の雑関数 dump() - Going My C Way を含むブックマーク はてなブックマーク -  テスト用の雑関数 dump() - Going My C Way  テスト用の雑関数 dump() - Going My C Way のブックマークコメント

テスト用に使おうと思いメモリ内容をダンプする dump() を作成します。

ソース dump.c

#include <stdio.h>      /* printf()  */
#include <string.h>     /* memset()  */
#include <stddef.h>     /* size_t    */
#include <ctype.h>      /* isprint() */

#define WIDTH   (16)

const void *dump(const void *addr, size_t bytes)
{
    const unsigned char *p = addr;
    char text[WIDTH+1];
    unsigned i = 0;

    while (i < bytes) {
        if ((i % WIDTH) == 0) {
            printf("%6d: ", i);

            memset(text, '\0', sizeof(text));
        }


        printf("%02x ", *p);

        text[i % WIDTH] = isprint(*p) ? *p : '.';

        p++; i++;


        if ((i % WIDTH) == 0) {
            printf(": %s\n", text);
        }
    }

    if ((i % WIDTH) != 0) {
        printf("%*s: %s\n", (WIDTH - (i % WIDTH)) * 3, " ", text);
    }

    return addr;
}

/*
    ここから下はテスト用の main 関数
*/
#if defined(TEST_MAIN)

#include <stdlib.h>     /* EXIT_SUCCESS */
#include <string.h>     /* strlen()     */

int main(int argc, char *argv[])
{
    const char *msg = (argc > 1) ? argv[1] : "hello, world\n";

    dump(msg, strlen(msg));

    return EXIT_SUCCESS;
}

#endif /* defined(TEST_MAIN) */

テスト用のバイナリを make。

$ make CFLAGS=-DTEST_MAIN dump

テスト。

$ ./dump 
     0: 68 65 6c 6c 6f 2c 20 77 6f 72 6c 64 0a          : hello, world.

$ ./dump  ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890
     0: 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 : ABCDEFGHIJKLMNOP
    16: 51 52 53 54 55 56 57 58 59 5a 61 62 63 64 65 66 : QRSTUVWXYZabcdef
    32: 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 : ghijklmnopqrstuv
    48: 77 78 79 7a 31 32 33 34 35 36 37 38 39 30       : wxyz1234567890

OK。

今後使うためアーカイブ(静的ライブラリ)を作成します。

$ make CFLAGS="-Wall -Wextra" dump.o
$ ar rv libtestmisc.a dump.o                  # アーカイブ作成
$ ls libtestmisc.a
libtestmisc.a

libtestmisc.a が出来ました。

ヘッダ testmisc.h も作成します。
#ifndef INCLUDED_TESTMISC_H
#define INCLUDED_TESTMISC_H

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

#include <stddef.h> /* size_t */

/*
    prototypes
*/
const void *dump(const void *addr, size_t bytes);


#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* ! INCLUDED_TESTMISC_H */
リンクのテスト
libtestmisc.a のリンクテストをします。テスト用のソース try.c。
#include <stdio.h>          /* printf()     */
#include <stdlib.h>         /* EXIT_SUCCESS */
#include <string.h>         /* strlen()     */
#include "testmisc.h"

#define nl()    (printf("\n"))

int main(void)
{
    const char *msg1 = "hello, world\n";
    const char *msg2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                       "abcdefghijklmnopqrstuvwxyz"
                       "1234567890";
    const char *msg3 = "";

    dump(msg1, strlen(msg1));
    nl();
    dump(msg2, strlen(msg2));
    nl();
    dump(msg3, strlen(msg3));

    return EXIT_SUCCESS;
}
ビルド
$ make CFLAGS=-L. LDLIBS=-ltestmisc try
テスト。
$ ./try 
     0: 68 65 6c 6c 6f 2c 20 77 6f 72 6c 64 0a          : hello, world.

     0: 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 : ABCDEFGHIJKLMNOP
    16: 51 52 53 54 55 56 57 58 59 5a 61 62 63 64 65 66 : QRSTUVWXYZabcdef
    32: 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 : ghijklmnopqrstuv
    48: 77 78 79 7a 31 32 33 34 35 36 37 38 39 30       : wxyz1234567890
OK。
共有ライブラリ
libtestmisc.a の代わりに共有ライブラリを作成する場合は、以下のようにします。
$ rm dump.o
$ make CFLAGS="-Wall -Wextra -fPIC" dump.o
$ gcc -shared -o libtestmisc.so dump.o
$ ls libtestmisc.so
libtestmisc.so*
これで libtestmisc.so が出来ます。 libtestmisc.so をリンクする場合は以下です。(アーカイブのときと同じ)
make CFLAGS=-L. LDLIBS=-ltestmisc try
ただし、実行する場合はシステムに共有ライブラリのパスを知らせておく必要があります。環境変数を設定しておけばよいです。
$ export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH 
確認。
$ ldd try
	linux-gate.so.1 =>  (0x00cd4000)
	libtestmisc.so => ./libtestmisc.so (0x001c3000)
	libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x0034b000)
	/lib/ld-linux.so.2 (0x0011c000)
OK。libtestmisc.so が見つけられないと以下のようになります。
$ ldd try
	linux-gate.so.1 =>  (0x0097c000)
	libtestmisc.so => not found
	libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00d9c000)
	/lib/ld-linux.so.2 (0x0036f000)
libtestmisc.so をリンクしていない(libtestmisc.a をリンク)場合はエントリは表示されません。
$ ldd try
	linux-gate.so.1 =>  (0x0097c000)
	libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00d9c000)
	/lib/ld-linux.so.2 (0x0036f000)
libtestmisc.so が見つけられない場合、try の実行時に エラーになります。
$ ./try
./try: error while loading shared libraries: libtestmisc.so: cannot open shared object file: No such file or directory
コンパイル時に libtestmisc.so と libtestmisc.a が両方見つかると *.so がリンクされます。*.a をリンクしたつもり間違ってコンパイルすると実行時に上記のエラーになることがあります。

今後は

この日記では今後アーカイブ(*.a)のほうを使っていきます。