ICON of RYUUO.COM TradeMark

makeの作成

会員登録(SSL)
会員専用(SSL)




基礎: Makefile

自分で作るMakefile

$ gcc -c detail.cpp
$ gcc -o test test.cpp detail.o
のMakefileを作る



最初だけ詳しく説明を載せます。とは言っても私はMakeの専門家ではなく専門的な問題は他の書かgmakeのソースファイルを当たってください。
それでは始めます。makeは最初の依存関係だけを見ます。最初の例では
all: test.cpp detail.o
の部分です。allに対してtest.cpp detail.oとが依存しているとMakeは理解します。それで、今度はtest.cppを探しますが見当たりません。その次はdetail.oを探します。detail.oはdetail.cppに依存していてdetail.oを作るために
$(CXX) -c detail.cpp
を実行します。そして、最終的に
$(CXX) test.cpp detail.o -o test
を実行することが分かります。個別に一部分を実行したい時には
make detail.o
meke clean
ということになります。抜けは無いと思いますが・・・?


#CFLAGS = -g -Wall
#CFLAGS = 

CXX = g++

all: test.cpp detail.o
[Tab key]$(CXX) test.cpp detail.o -o test
[Tab key]の部分は以下略す
detail.o: detail.cpp
	$(CXX) -c detail.cpp

clean:
	rm -f detail.o test



同じく、このようにも書くことができます。



CXX = g++

test: test.o detail.o
	$(CXX) test.o detail.o -o test 

test.o: test.cpp
	$(CXX) -c test.cpp

detail.o: detail.cpp
	$(CXX) -c detail.cpp

clean:
	rm -f detail.o test.o test




今度は、$@ $< $^を使ってみよう



CXX = g++
# $^は依存関係全てを並べる
# $<は依存関係の先頭の一つを並べる
test: test.o detail.o
	$(CXX) $^ -o $@ 

test.o: test.cpp
	$(CXX) -c $<

detail.o: detail.cpp
	$(CXX) -c $<

clean:
	rm -f detail.o test.o test





ちょっと複雑になる

ここでは、記号$@ $< $?が難しいですが、fileの修正・変更をした時など勝手に依存関係を調査してくれるということです。
.cpp.oは***.cppファイルから***.oを生成する時のコマンドです。
${delete_SOURCES:.cpp=.o}は.cppの部分を.oに置き換えたものになります。


CFLAGS = -g -Wall
LIBS = -liconv

mybin_bindir = ..
mybin_bin_PROGRAMS = delete query insert

CXX = g++

delete_SOURCES = delete.cpp stream.cpp conm.cpp
query_SOURCES = query.cpp stream.cpp conm.cpp
insert_SOURCES = insert.cpp stream.cpp

all: ${mybin_bin_PROGRAMS}

.cpp.o:
        ${CXX} ${CFLAGS} -c $<

delete: ${delete_SOURCES:.cpp=.o}
        ${CXX} -o $@ $^ ${LIBS}
query: ${query_SOURCES:.cpp=.o}
        ${CXX} -o $@ $^ ${LIBS}
insert: ${insert_SOURCES:.cpp=.o}
        ${CXX} -o $@ $^ ${LIBS}

install: ${mybin_bin_PROGRAMS}
        cp ${mybin_bin_PROGRAMS} ${mybin_bindir}

clobber: 
        rm -f *.o ${mybin_bin_PROGRAMS}
	cd ${mybin_bindir};
	rm ${mybin_bin_PROGRAMS}




実践: MAKE

実際にやってみる!
program(hello)は、hello_dataというデータファイルのパスが記入されているhello.confを読み込んだ後、hello_dataというファイルにアクセスしそのファイルに書かれている文字列を出力するプログラムで、実に単純であるがmakeを理解する上には格好のプログラムである。我ながら、すごいとは思わないが。


$ ls -l
合計 48
8月  5 09:48 Makefile
8月  5 09:47 hello.c
8月  5 09:43 hello.conf
8月  5 20:05 hello.ico
8月  5 08:04 hello_data
$


emacs hello.conf

/home/${user}/ex/lib

${user}の部分は各自のLoginNameだ。たった、この一行だ。




hello.icoの説明はいらないだろう。

emacs hello_data

こんにちわ !

たった、この一行だ。




emacs hello.c

#include 
#include 
#include 
#include 
#include 

#define BUFSIZE 256


char DATA[128];
char CFG[128];




int main(){
  
  int fd;
  const char *HOME;  /*** 環境変数から FULL PATH を取得する   ***/
  char *HOME_DIR;    /*** ${HOME}/ex を home directoryにする  ***/


  /*** 環境変数から FULL PATH を取得 ***/
  HOME = getenv("HOME");

  /*** HOME_DIRECTRYの  FULL PATH を取得  ***/
  strcpy(HOME_DIR, HOME);
  strcat(HOME_DIR, "/ex");  // hello home

  /*  
   *  hello.confの  FULL PATH を取得  
   *  hello.confは ${HOME}/etcにInstallする
   */
  strcpy(CFG,HOME_DIR);
  strcat(CFG,"/etc/hello.conf");


  
  if( (fd=open(CFG, O_RDONLY, 0644)) <0){
    perror("open");
    exit(EXIT_FAILURE);
  }


  int rd;
  char read_buf[BUFSIZE];
  char ch[512];
  ch[0]='\0';


  while( 0<(rd=read(fd, read_buf, sizeof(read_buf))) ){
    if(rd==BUFSIZE){
      strcat(ch,read_buf);
      ch[strlen(ch)-1]='\0';
    }else{
      strncat(ch,read_buf,rd);
      strcat(ch,"\0");
    }
  }

  read_buf[0]='\0';
  close(fd);


  /*** hello_dataの  FULL PATH を取得  ***/
  strncpy(DATA,ch,strlen(ch)-1);  
  strcat(DATA,"/hello_data");

  if( (fd=open(DATA, O_RDONLY, 0600)) <0){
    printf("fd==%d\n",fd);
    perror("open");
    exit(EXIT_FAILURE);
  }


  ch[0]='\0';

  while( 0<(rd=read(fd, read_buf, sizeof(read_buf))) ){
    if(rd==BUFSIZE){
      strcat(ch,read_buf);
      ch[strlen(ch)-1]='\0';
    }else{
      strncat(ch,read_buf,rd);
      strcat(ch,"\0");
    }
  }

  read_buf[0]='\0';
  close(fd);

  printf("%s\n",ch);

}

emacs Makefile

CC = gcc
CFLAGS =
LIBS =


hello_dir = ${HOME}/ex
hello_PROGRAMS = hello


hello_SOURCES = hello.c

extra_DIST = hello.conf hello_data hello.ico

cfg_dir = ${hello_dir}/etc
data_dir = ${hello_dir}/lib

dist_cfg_DATA = hello.conf
dist_data_DATA = hello_data
dist_ico_DATA = hello.ico


all: ${hello_PROGRAMS}


.c.o:
	${CC} ${CFLAGS} -c $<

hello: ${hello_SOURCES:.cpp=.o}
	${CXX} -o $@ $^ ${LIBS}	



install:
	test -d ${hello_dir} || mkdir ${hello_dir}
	cp ${hello_PROGRAMS} ${hello_dir}
	test -d ${cfg_dir} || mkdir ${cfg_dir}	
	cp -p ${dist_cfg_DATA} ${cfg_dir}
	test -d ${data_dir} || mkdir ${data_dir}
	cp -p ${dist_data_DATA} ${data_dir}
	cp -p ${dist_ico_DATA} ${hello_dir}

uninstall: 
	rm -f *.o ${hello_PROGRAMS}
	cd ${hello_dir}; rm ${hello_PROGRAMS}
	cd ${cfg_dir}; rm ${dist_cfg_DATA}
	cd ${data_dir}; rm ${dist_data_DATA}

test -d ${hello_dir} || mkdir ${hello_dir}...の意味が理解できないひとの為に付き足せば、
A && B || C ...の構文は Aが真ならばB 偽ならばCという構文だ。この場合、test -d ${hello_dir}
という条件(directoryが存在)が真ならばにあたる部分が無く、無ければdirectoryをつくるということ
になる。




$ make
$ make install

$ ls -l ${HOME}/ex
合計 36
drwxrwxr-x 2 4096  8月  5 08:18 etc
-rwxrwxr-x 1 6992  8月  5 09:49 hello
-rwxr-xr-x 1 2469  7月  8 20:05 hello.ico
drwxrwxr-x 2 4096  8月  5 08:18 lib

$ cd ${HOME}/ex
$ ./hello
こんにちわ !

$ 



autoconf & automake
GTK2 を使用する場合は...茶色で示してあります。

$ ls -a
helloworld.c
$ autoscan
autom4te: configure.ac: no such file or directory
autoscan: /usr/bin/autom4te failed with exit status: 1
$ ls -a
autoscan.log configure.scan helloworld.c
$ mv ./configure.scan ./configure.in
-------------------- configure.in の書き換え-----------------------
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ(2.57)
AC_INIT(helloworld.cpp, 1.0.0, ******@ryuuo.com) <---この部分
AC_CONFIG_SRCDIR([helloworld.c])
AC_CONFIG_HEADER([config.h])

### この部分は後で追加する
#AM_INIT_AUTOMAKE(helloworld, 1.0.0, no-define)
###

# Checks for programs.
AC_PROG_CC


# -------------- gtk+ を使用する場合
AM_PATH_GTK(1.2.0, CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$LIBS $GTK_LIBS",
AC_MSG_ERROR(GTK+1.2.0 not found.))

AM_PATH_GTK_2_0(2.0.0, CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$LIBS $GTK_LIBS",
AC_MSG_ERROR(GTK+2.0.0 not found.))
# --------------

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.
AC_OUTPUT([Makefile]) <---この部分

--------------------------- end --------------------------

$ autoheader
$ ls -a
. .. autom4te.cache autoscan.log config.h.in configure.in helloworld.c
$ touch NEWS README AUTHORS ChangeLog
$ ls -a
. AUTHORS NEWS autom4te.cache config.h.in helloworld.c
.. ChangeLog README autoscan.log configure.in
---------------- Makefile.am の作成 ----------------

bin_PROGRAMS = helloworld test
helloworld_SOURCES = helloworld.c
test_SOURCES = test.c
INCLUDES = ${GTK_CFLAGS}
helloworld_LDADD = ${GTK_LIBS}


# autoconf & automake で 静的ライブラリを
# リンカーに伝えるためには.......
# $ g++ -o test test.c test_assist.o -lpthread
# で、コンパイルしたい時には
#

test_LDADD = -lpthread

# Makefile.am に関しての蘊蓄
# $ make distで、配付するtar.gzなどのファイルが生成されるが、このファイルには
# ソースファイルとAUTHORS NEWS ChangeLog READMEのファイルしか梱包されない。
# その他のファイルを梱包するには、の説明です。
#

EXTRA_DIST = example.sh

# このように記述しておけば一緒に梱包してくれます。
# 次に考えるのがinstall場所です。

dist_bin_SCRIPTS = example.sh

# このように記述すれば/usr/local/binにinstallしてくれます。
# 次に考えるのがinstallする場所の変更です。
# 最終的な記述は

EXTRA_DIST = example.sh
example_dir = ${PREFIX}/example
dist_example_SCRIPTS = example.sh

# その他、SCRIPTS(プライマリというそうです)に使える変数には
# DATA HEADERS MANS TEXINFOS PROGRAMSLIBRAIES などだ。

-------------------- end ----------------------



--------------- configure.in の修正 -----------------
AC_CONFIG_HEADER([config.h]) を
AM_CONFIG_HEADER([config.h]) に書き変え
また、
AM_INIT_AUTOMAKE(helloworld, 1.0.0, no-define)
を追加し
--------------- end -----------------



===== gtk+ を使用する場合 =====

$ cp /usr/share/aclocal/gtk.m4 ./acinclude.am
$ cp /usr/share/aclocal/gtk-2.0.m4 ./acinclude.am


fileが無い場合は
rpm -qa | grep gtk2-devel
を確認してみては?
------------------- acinclude.am の修正 -----------------------

# Configure paths for GTK+
# Owen Taylor 1997-2001

dnl AM_PATH_GTK_2_0([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]])

AM_PATH_GTK(1.2.0, CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$LIBS $GTK_LIBS",
AC_MSG_ERROR(GTK+1.2.0 not found.))
AM_PATH_GTK_2_0(2.0.0, CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$LIBS $GTK_LIBS",
AC_MSG_ERROR(GTK+2.0.0 not found.))


dnl Test for GTK+, and define GTK_CFLAGS and GTK_LIBS, if gthread is specified in MODULES,

------------------- end ---------------------



$ aclocal
$ automake -a
configure.in: installing `./install-sh'
configure.in: installing `./mkinstalldirs'
configure.in: installing `./missing'
Makefile.am: installing `./INSTALL'
Makefile.am: installing `./COPYING'
Makefile.am: installing `./depcomp'
$ autoconf
$ ls -a
. ChangeLog NEWS autoscan.log depcomp mkinstalldirs
.. INSTALL README config.h.in helloworld.c
AUTHORS Makefile.am aclocal.m4 configure install-sh
COPYING Makefile.in autom4te.cache configure.in missing

あとは

$ ./configure
$ make
$ make install
で、上手く行くと思います。


参考にしたWebPage:
http://sources.redhat.com/automake/automake.html