CPK 2.2 configure.in, config.mk.in, platform.h.in 작성

gurugio의 이미지

점점 쓸데없이 길어집니다.. 문맥도 혼란스럽고 뒤죽박죽이 되갑니다..
관심좀 주세요 :-(

CPK 2.2 configure.in, config.mk.in, platform.h.in 작성
configure의 가장 큰 목적은 플랫폼 환경을 분석해서 프로그램이 플랫폼 환경에 상관없이 일정하게 동작하도록 해주는 것입니다. 사용자가 프로그램을 빌드하고자하는 환경은 아주 다양합니다. 운영체제가 32비트이거나 64비트일 수 있고, 헤더 파일의 위치가 다르거나, 운영체제 자체가 다를 수 있습니다. 또 프로그램을 빌드하기 위해서는 libabc.so 라는 라이브러리가 있어야하고, abc.h라는 헤더가 있어야 하는데 이런 다양한 환경을 찾아내서 지금 빌드할 플랫폼이 어떤 환경인지를 찾아내는 것이 configure의 임무입니다.

configure는 실행 프로그램은 아니고 쉘 스크립트입니다. 그리고 configure라는 쉘 스크립트를 간단하게 만들 수 있도록 해주는 프로그램이 autoconf입니다. configure.in 이라는 텍스트 파일에 autoconf의 사용 문법에 맞게 스크립트 파일을 작성하고 autoconf를 실행하면 configure 파일을 생성해줍니다.

따라서 우리도 이런 목적에 맞게 플랫폼의 환경을 찾아내도록 configure.in 파일을 작성해야합니다. configure.in을 작성할 때 일반적으로 다음과 같은 일을 하도록 작성합니다.

- 빌드/실행에 필요한 유틸리티의 설치 유무 확인
- 컴파일러/링커 등 빌드툴의 버전과 옵션 확인
- 헤더 파일 존재 확인
- 운영체제 비트 확인
- 확인된 사항들을 Makefile이나 .h 로 저장

참고로 configure.in의 주석은 dnl이나 #로 시작합니다. 예제 파일에서는 dnl #로 주석을 표시했는데 emacs에서 dnl을 잘 인식하지 못해서 #표시를 추가해준 것입니다. dnl만 써도 주석으로 인식합니다.

그리고 autoconf에서 제공하는 매크로는 굉장히 다양합니다. 대부분 AC_로 시작하는 이름을 가지고 있습니다. 너무나 다양하기 때문에 일일이 찾기도 힘듭니다. 저는 autoconf의 메뉴얼을 잠깐 찾아보고 원하는 매크로를 찾기 어려우면 그냥 bash 쉘 스크립트로 작성해서 configure.in에 집어넣습니다. autoconf 버전에 따라 실행이 안되는 매크로도 있습니다. 너무 모든 매크로를 사용하려고 할 필요없이 쉘 스크립트를 이용하는 편이 더 간단할 때가 있습니다.

예제 파일을 보면서 설명을 하겠습니다. 예제 파일을 보면 각 매크로의 사용 방법을 간략하게 아실 수 있을 것입니다. 자세한 사용법은 메뉴얼을 보시면 됩니다만 사용 예를 알면 메뉴얼 보시기에도 더 편할 것입니다.

dnl # Initialize configure
AC_INIT(calib, 1.0)
configure를 초기화합니다. AC_INIT은 configure.in 파일에서 가장 먼저 실행되야 할 매크로입니다. calib은 제가 임의로 지정한 패키지 이름이고, 1.0은 calib 패키지의 버전입니다. 자신이 원하는 이름과 버전을 사용하면 됩니다. 패키지 이름은 configure --help를 실행해서 확인할 수 있습니다. 이 예제를 실행하면 다음과 같은 메시지가 출력됩니다.

`configure' configures calib 1.0 to adapt to many kinds of systems.

dnl # Check required autoconf version

AC_PREREQ([2.13])
이 파일은 2.13이상의 autoconf에서만 처리될 수 있습니다.

dnl # platform output file
AC_CONFIG_HEADER([./include/platform.h])
configure.in에서는 일반적인 쉘 스크립트와 같이 변수를 만들어서 사용할 수 있습니다. 그리고 이 변수들의 값을 다른 파일에 써놓을 수 있습니다. 이렇게 변수들을 출력할 헤더파일의 이름을 지정합니다. ./include/platform.h.in 파일에 원하는 변수 이름을 써놓으면 configure가 파일을 읽고 ./include/platform.h를 생성해줍니다.

dnl # tools

dnl # gawk
AC_PROG_AWK
gnu awk 툴이 설치되어있는지 확인합니다.

dnl # nasm install check
AC_PATH_PROG([NASM], [nasm])
nasm이라는 어셈블러가 설치되어 있는지 확인합니다. 환경 변수 PATH에 지정된 디렉토리들을 찾아다니면서 nasm이라는 실행파일을 확인합니다. 파일을 찾으면 NASM 변수에 /usr/bin/nasm과 같이 파일의 절대 경로를 저장합니다.

if test -z "$NASM"; then
AC_MSG_ERROR([Cannot find Netwide Assembler])
fi
AC_MSG_ERROR은 에러 메시지를 출력하고 configure를 중단하는 매크로입니다. nasm 파일을 찾지 못하면 NASM이라는 변수에 아무것도 저장되지 않으므로 에러를 확인할 수 있습니다. 이와같이 쉘 스크립트와 autoconf의 매크로를 적절히 섞어서 사용할 수 있습니다.

dnl # nasm version check
AC_MSG_CHECKING([whether NASM version >= 2.0 for 64bit assembly])
AC_MSG_CHECKING 매크로는 configure 실행시 무엇인가를 확인중이라는 안내 메시지입니다. 이 메시지는 checking 으로 시작되고 ...로 끝나는 메시지를 출력합니다. 따라서 이 코드는 checking whether NASM version >= 2.0 for 64bit assembly... 메시지를 출력합니다. 이 다음으로는 yes나 no를 출력하는 것이 일반적인 형태입니다.

${NASM} -v | grep version > nasm_version.tmp
nasm -v 명령을 실행해서 버전 정보를 파일에 기록합니다. NASM version 2.07 compiled on Nov 5 2009 와 같은 메시지가 저장됩니다.

result=`cat nasm_version.tmp | awk '{print $3}'`
세번째 컬럼에 있는 2.07이라는 숫자를 뽑아냅니다.

nasm_major=`echo $result | awk -F . '{print $1}'`
rm -f nasm_version.tmp
nasm_major 변수에 버전 숫자를 저장하고 파일을 지웁니다.

if test "$nasm_major" -lt 2; then
AC_MSG_ERROR([nasm version is below than 2.0])
else
AC_MSG_RESULT([yes])
fi
2.07은 2보다 크므로 yes라는 메시지를 출력합니다. 만약 버전이 맞지 않다면 AC_MSG_ERROR매크로가 실행됩니다. AC_MSG_ERROR은 메시지를 출력하고 configure 의 실행을 중단시킵니다.

AC_SUBST(NASM)
config.mk 파일에 NASM이라는 변수의 값을 저장합니다. 자세한 사항은 config.mk 작성에서 다시 설명하겠습니다.

dnl # gcc install
AC_PROG_CC
gcc가 설치되어있는지 확인합니다. gcc가 설치되어있으면 CC변수를 gcc로 설정합니다.

if test -z "$CC"; then
CC=gcc
fi
CC변수가 따로 설정되어있지 않으면 gcc를 저장합니다. AC_PROG_CC가 CC변수를 설정하겠지만, 만약을 대비해서 넣은 코드입니다. 리눅스 하나의 플랫폼에서만 사용할 때는 이렇게 중복된 코드를 넣을 필요가 없습니다. 하지만 다양한 유닉스 플랫폼에서 동작할 때는 이렇게 다시한번 확인하는 코드가 필요합니다. 플랫폼에따라 어떻게 동작할지 확실치가 않기 때문입니다. 10개의 플랫폼에서 동작해도 1개의 플랫폼에서 약간 다르게 동작한다면, 여기에도 대비해야합니다.

dnl
AC_MSG_CHECKING([whether GCC version >= 4.0])
gcc의 버전 확인을 시작합니다.

${CC} -v 2> gcc_version.tmp
버전 메시지를 파일에 저장합니다.

result=`grep "gcc version" gcc_version.tmp | awk '{print $3}'`
여러 줄의 메시지에서 gcc version이 포함된 부분을 따로 저장합니다.

rm -f gcc_version.tmp
이제 파일은 필요없습니다.

gcc_major=`echo $result | awk -F . '{print $1}'`
gcc_minor=`echo $result | awk -F . '{print $2}'`
gcc_minor_minor=`echo $result | awk -F . '{print $3}'`
.로 구분된 숫자중에서 첫번째 숫자가 메이저 번호입니다. 두번째는 마이너번호입니다.

if test "$gcc_major" -ge 4 && test "$gcc_minor" -ge 0
then
AC_MSG_RESULT([yes ("$result")])
else
echo "current gcc is \"${CC}\"-${gcc_major}.${gcc_minor}.${gcc_minor_minor}"
echo "you can define gcc as \"CC=your-gcc ./configure\""
AC_MSG_ERROR([current gcc version cannot process 64bit address])
fi
버전이 4.0 이상이 되어야 통과합니다. 버전이 4.0보다 낮으면 현재 gcc의 버전을 알려주면서 configure를 중단합니다. 꼭 4.0 이상일 필요는 없지만 64비트 컴파일을 위해서 4.0 이상을 쓰면 좋습니다. 4.0이하에서는 메모리 어드레싱과 관련해서 가끔 에러가 발생한다고 알려져있습니다.

AC_SUBST(CC)
config.mk에 CC의 값을 저장합니다.

dnl # ld support x86_64
AC_MSG_CHECKING([whether ld supports elf_x86_64])
링커 ld가 64비트를 지원하는지 확인하겠습니다.

if test -z "${LD}" ; then
LD=ld
fi
LD변수에 링커의 이름 ld를 저장합니다.

result=`${LD} -V | grep x86_64`
대문자 V 옵션은 ld가 지원하는 플랫폼의 리스트를 출력합니다. 이 중에 x86_64가 있는지 확인합니다.

if test -z "$result" ; then
echo "current ld is \"${LD}\""
echo "you can define ld as \"LD=your-ld ./configure\""
AC_MSG_ERROR([current ld do not support elf_x86_64, please install 64bit ld])
else
AC_MSG_RESULT([yes])
fi

AC_SUBST(LD)
x86_64를 지원하면 config.mk에 LD 값을 저장합니다.

dnl # objcopy support x86_64
AC_MSG_CHECKING([whether objcopy supports elf64-x86-64])

if test -z "$OBJCOPY" ; then
OBJCOPY=objcopy
fi

result=`${OBJCOPY} -h | grep elf64-x86-64`

if test -z "$result" ; then
echo "current objcopy is \"${OBJCOPY}\""
echo "you can define objcopy as \"OBJCOPY=your-objcopy ./configure\""
AC_MSG_ERROR([current objcopy do not support elf-x86-64, please install
64bit objcopy])
else
AC_MSG_RESULT([yes])
fi

AC_SUBST(OBJCOPY)
gcc,ld,objcopy 모두 64비트 x86_64 플랫폼을 지원하는지 확인합니다.

dnl # extra tools
AC_PATH_PROG([DD], [dd])
AC_PATH_PROG([NM], [nm])
dd와 nm 툴을 확인합니다. 꼭 빌드과정에 사용되는 것은 아니지만 개발하다보면 자주 쓰는 툴이므로 항상 체크해줍니다.

AC_SUBST(DD)
AC_SUBST(NM)

dnl # headers
AC_CHECK_HEADERS(execinfo.h mcheck.h malloc.h pthread.h stdio.h stdlib.h string.h signal.h unistd.h stdint.h)
AC_CHECK_HEADERS(sys/types.h sys/stat.h sys/fcntl.h sys/wait.h)
헤더 파일이 설치되어있는지 확인합니다.

dnl # host

AC_CANONICAL_HOST()
현재 빌드하고있는 플랫폼의 타입을 알아냅니다. host, host_os, host_cpu, host_vendor 등의 변수에 플랫폼 값을 저장합니다. 예를 들어 제가 사용하는 노트북에서는 host변수의 값이 x86_64-unknown-linux-gnu입니다. -로 구분해서 첫번째 필드의 값 x86_64가 host_cpu의 값입니다. 두번째 필드 unknown은 host_vendor 값이고, linux_gnu는 host_os 변수의 값입니다.

echo ""
echo "HOST PLATFORM: ${host}"
echo "HOST OS: ${host_os}"
echo "HOST CPU: ${host_cpu}"

echo "HOST VENDOR: ${host_vendor}"
echo ""

CALIB_CFG_CPU="$host_cpu"
CALIB_CFG_CPU_BIT=0
CALIB_CFG_OS="$host_os"
이름이 CALIB_CFG_로 시작되는 변수들은 다른 Makefile나 C 소스들이 플랫폼의 상태를 알 수 있도록 config.mk나 platform.h 파일에 출력될 변수들입니다.

case "${host}" in
i[3456]86-* )
CALIB_CFG_CPU_BIT=32
;;
amd64-*-* )
CALIB_CFG_CPU_BIT=64
;;
x86_64-* )
CALIB_CFG_CPU_BIT=64
;;
esac

host값에 따라 CPU의 비트를 알 수 있습니다.

AC_DEFINE_UNQUOTED(CALIB_CFG_OS, "$CALIB_CFG_OS")
AC_DEFINE_UNQUOTED(CALIB_CFG_CPU_$CALIB_CFG_CPU, 1)
AC_DEFINE_UNQUOTED(CALIB_CFG_CPU, "$CALIB_CFG_CPU")
AC_DEFINE_UNQUOTED(CALIB_CFG_CPU_BIT_$CALIB_CFG_CPU_BIT, 1)
AC_DEFINE_UNQUOTED(CALIB_CFG_CPU_BIT, "$CALIB_CFG_CPU_BIT")
platform.h.in에는 #undef CALIB_CFG_OS 등으로 변수들이 선언되어 있습니다. AC_DEFINE_UNQUOTED 매크로를 사용하면 변수 선언을 #define으로 바꾸고 그 값을 정의합니다. 결국 platform.h에는 #define CALIB_CFG_OS linux-gnu로 저장됩니다.

AC_SUBST(CALIB_CFG_CPU)
AC_SUBST(CALIB_CFG_CPU_BIT)
config.mk에 저장될 변수들입니다.

AC_OUTPUT([config.mk])
config.mk를 작성합니다.

dnl # remove temporary files
rm -f ./config.cache ./config.log ./config.status
configure의 동작에 필요없는 파일은 지웁니다.

이렇게 configure.in 파일을 작성했다면 config.mk.in을 작성합니다. config.mk.in은 다른 Makefile들이 참조해서 쓸 수 있는 변수들을 선언하는 파일입니다.

# This file is set by configure
HOST=@host@
OS=@host_os@
CPU=@CALIB_CFG_CPU@
NASM=@NASM@
GCC64=@CC@
LD64=@LD@
OBJCOPY64=@OBJCOPY@
DD=@DD@
NM=@NM@

변수이름=변수값 형태로 변수를 선언합니다. 변수는 Makefile에서 사용할 변수입니다. configure.in에서 만든 변수들은 @변수이름@으로 참조됩니다. configure는 실행이 완료된 후 자신이 가진 변수 값을 config.mk.in에 출력해서 config.mk 파일을 생성합니다. configure에서 조사한 플랫폼 정보나 툴에 대한 정보 등을 빌드 프로세스에서 사용하고자할 경우에 이렇게 .mk파일을 작성하게됩니다. 앞으로 Makefile을 만들 때 이 정보들을 사용해서 어디에 있는 어떤 툴을 사용할지 결정하게 됩니다.

예를 들어 제 컴퓨터에서 생성된 config.mk를 보여드리겠습니다.

# This file is set by configure
HOST=x86_64-unknown-linux-gnu
OS=linux-gnu
CPU=x86_64
NASM=/usr/bin/nasm
GCC64=gcc
LD64=ld
OBJCOPY64=objcopy
DD=/bin/dd
NM=/usr/bin/nm

이제 platform.h.in 파일을 만들겠습니다. .mk파일이 Makefile에 포함되고 빌드 과정에서 사용된다면 .h 파일은 소스가 참고할 정보들을 저장한다는 차이가 있습니다. configure에서 알아낸 정보를 소스 파일에 전달하게 됩니다.

platform.h.in 파일을 보겠습니다.

#undef CALIB_CFG_OS
#undef CALIB_CFG_CPU_x86_64
#undef CALIB_CFG_CPU_i386
#undef CALIB_CFG_CPU_AMD64
#undef CALIB_CFG_CPU
#undef CALIB_CFG_CPU_BIT
#undef CALIB_CFG_CPU_BIT_32
#undef CALIB_CFG_CPU_BIT_64

configure에서 정의한 변수들이 #undef으로 선언되어 있습니다. configure.in 파일에서 보듯이 AC_DEFINE_UNQUOTED 매크로를 이용해서 #undef를 #define으로 바꾸고 정의할 값을 지정합니다.

예를 들면 configure.in 파일에서 AC_DEFINE_UNQUOTED(CALIB_CFG_OS, "$CALIB_CFG_OS")를 호출했었습니다. platform.h.in에서 CALIB_CFG_OS 선언을 #define으로 바꾸고 상수 값을 configure에서 만든 변수중에서 CALIB_CFG_OS 변수의 값으로 설정하라는 것입니다. 변수 이름이 같아서 혼란스럽지만 동일한 변수이름을 사용해서 같은 정보라는 것을 알기 쉽도록 하기 위해 일부러 같은 이름을 사용했습니다.

제 컴퓨터에서 생성된 platform.h 파일을 보여드리겠습니다.

/* ./include/platform.h. Generated from platform.h.in by configure. */
#define CALIB_CFG_OS "linux-gnu"
#define CALIB_CFG_CPU_x86_64 1
/* #undef CALIB_CFG_CPU_i386 */
/* #undef CALIB_CFG_CPU_AMD64 */
#define CALIB_CFG_CPU "x86_64"
#define CALIB_CFG_CPU_BIT "64"
/* #undef CALIB_CFG_CPU_BIT_32 */
#define CALIB_CFG_CPU_BIT_64 1

지금까지 include, lib, src, test 디렉토리를 만들고 configure.in, config.mk, include/platform.h.in 파일을 만들었습니다. 이제 configure.in을 가지고 configure 파일을 만들어보겠습니다. configure.in 파일이 있는 디렉토리에서 autoconf 명령을 실행합니다. 아무런 메시지가 없이 종료되었다면 정상적으로 실행된 것입니다. configure.in 파일에 문제가 있다면 문제가 발생한 위치와 설명을 출력합니다. ls를 실행해보면 autom4te.cache 디렉토리와 config.log, configure 파일이 생성된 것을 확인할 수 있습니다. 이제 configure를 실행합니다.

경우에따라 configure를 실행했는데 다음과 같이 install-sh 파일이나 config.sub 파일이 없다는 에러가 발생할 수 있습니다.

configure: error: cannot find install-sh, install.sh, or shtool in "." "./.." "./../.."
configure: error: cannot run /bin/bash ./config.sub

이럴때는 automake --add-missing 명령을 실행해보시기 바랍니다. automake 파일이 자동으로 config.guess, config.sub, install-sh 등 configure의 실행에 필요한 파일들을 설치해줍니다.

configure.in: no proper invocation of AM_INIT_AUTOMAKE was found.
configure.in: You should verify that configure.in invokes AM_INIT_AUTOMAKE,
configure.in: that aclocal.m4 is present in the top-level directory,
configure.in: and that aclocal.m4 was recently regenerated (using aclocal).
configure.in:121: installing `./config.guess'
configure.in:121: installing `./config.sub'
configure.in:121: installing `./install-sh'
automake: no `Makefile.am' found for any configure output

몇몇 버전의 automake는 install-sh 파일을 설치하지 않는 버그를 가지고 있습니다. 그럴때는 automake의 소스 파일안에있는 install-sh 파일을 직접 복사해서 사용하면 됩니다.

configure가 실행되면 최종적으로 다음과 같은 파일들을 가지게 됩니다. config.mk와 include/platform.h가 제대로 생성되었는지 파일 내용을 확인하시기 바랍니다.

$ ls *
config.guess config.mk config.mk.in config.sub configure configure.in install-sh

autom4te.cache/:
output.0 requests traces.0

include/:
platform.h platform.h.in

lib/:

src/:

test/:

댓글

bacon의 이미지

수고 하시네요. 그냥 제 의견 적어 볼께요. 관심을 부탁하셔서...

좀 더 최근의 autoconf/automake사용법으로 설명했으면 더 좋았을듯 합니다. 최근버전을 사용한다고 가정하고, 몇가지 생각나느대로 적어 봅니다.
* configure.in으로 해도 되지만 configure.ac가 현재 사용되는 이름이다.
* autoreconf를 사용해서 생성하는게 더 간단할듯 하다.
* 기왕 automake를 사용할 거라면 AM_INIT_AUTOMAKE를 넣어 주면 automake --add-missing같이 따로 실행할 필요도 없다.
* 새로 바뀐 매크로를 사용하자. 예를 들면, AC_OUTPUT([config.mk])대신에 AC_CONFIG_FILES([config.mk]) AC_OUTPUT

또 여러 플랫폼을 지원하기 위해서 autoconf/automake를 사용한다고 쓰셨는데, 안에 작성되어 있는 내용중에 몇몇부분이 그런거랑은 상관없이 gcc위주로 세팅되어 있는듯 합니다. 해당플랫폼에 gcc나 objcopy가 없는경우도 있는데말이죠. LD버전으로 64비트 지원여부를 판다한는것도 그런것 같고요. CALIB_CFG_CPU_BIT를 판단하는것도 아주 generic해 보이지는 않아요. 그외 사소한것들도 보이네요.

정확히 어떤 용도로 작성한것인지 몰라서 제 의견이 부적합할 수도 있겠습니다.

gurugio의 이미지

관심 정말정말정말 감사합니다 ;-)

답변을 하자면요.
1. *.in으로 그냥 통일해서 쓰자는 귀차니즘적인 마인드를 가지고 있습니다.
2. autureconf는 안써봐서 잘 모르지만 시도해보고 좋은 점이 있으면 내용을 수정하겠습니다.
3. 저는 automake를 쓰지 않고, 유사한 템플릿을 직접 만들어서 쓰고있습니다. 이번에만 스크립트 설치용으로 사용되고, 앞으로는 거론하지 않으려합니다.
4. 새로 바뀐게 뭔지 몰랐습니다. AC_CONFIG_FILES로 수정하겠습니다.
5. 전 여러 플랫폼이지만 공통적으로 gcc 및 gnu libtools를 사용하는 환경을 가정했습니다. 미리 설명하지 않은 실수가 있었습니다. 수정하겠습니다.
6. LD 버전으로 판단하는 것은 LD가 64비트를 지원하느냐이지 플랫폼이 64비트인지는 아닙니다. 그쪽 부분에 설명을 추가하겠습니다.
7. CALIB_CFG_CPU_BIT는 다시보니 정말 좀 거시기합니다. 다른 방법을 찾아보겠습니다. 너무 간단하게 하려다보니 좀 허술했습니다. 수정하겠습니다.

다른 사소한 것들도 더 써주시면 좋겠습니다...너무 공짜 심보인가요? ;-)

제가 늘 쓰던 버릇도 있고, 좀더 간단한 방법을 써야할지 더 확실한 방법을 써야할지 고민되는 부분들도 있고 그렇습니다.
사소한 것들이라도 의견을 주시면 제가 글쓰는 데도 힘이 되고,
나중에 혹시 보시는 분들도 좀더 좋은 정보를 얻으실 수 있으니 많은 사람들에게 큰 보탬이 되리라 믿습니다.

bacon의 이미지

사소할수록 논쟁의 여기가 있어서 말이죠...

1. AC_PROG_AWK해놓고 정작 gcc_major=`echo $result | awk -F . '{print $1}'`처럼 ${AWK}대신 awk를 사용한다.
2. grep "gcc version" gcc_version.tmp | awk '{print $3}'보다는 awk '/gcc version/ { print $3 }'하면 명령어 하나면 된다.
버릇인지 몰라도 이런분들 많더라고요. 예를 들어 grep string file하면 되는걸 cat file | grep string하는것 처럼 말이죠. 오버헤드가 꽤 큰데...

오랜된 매크로들은 autoupdate사용하면 오래된 형식을 최신으로 자동변환해주니까, 직접 매뉴얼 보고 하나 하나 찾을 필요는 없을것 같아요.
CALIB_CFG_CPU_BIT으로 포인터사이즈나 64bit지원 여부를 판단하려면 sizeof(void*)나 _LP64나 기타 유사한것을 테스트하면 간단할듯 해요. 더 복잡한 프로그램을 짜서 할수도 있겠지만요.

일반 유저스페이스에서 작업하시는 경우 autoconf+automake+libtool조합으로 사용하시면 참 편리한 부분이 많습니다. 이거 사용하지 않아도 ./configure --help하면 각종 디렉토리같은게 다 나오는데, prefix니 bindir이니 이런거 직접 다 지원하려면 생각보다 양이 많더라구요. automake사용하면 훨씬 쉬워지는듯해요. 또 위에 샘플이 라이브러리프로젝트니까 libtool사용해주면 shared라이브러리나 static라이브러리나 선택적으로 빌드도 가능할거구요. 나중에 rpm이나 deb같은거 만들때도 쉬어지고요.

개인적인 생각이므로 참고만 해주세요.

gurugio의 이미지

많은 참고가 되었습니다 ;-)

1,2번은 정말 제 실수입니다. 저도 아무생각이 없이 예전에 맹글어논걸 그대로 쓰고 있었네요.
64비트 판단하는건 좀더 생각해봐야할것 같습니다. 너무 복잡해지면
처음 접하시는 분들에게 거부감이 들거나 너무 어려울까봐요.

automake나 libtool이 일반적인 라이브러리를 만드는데는 참 편리하지요.
그런데 실제 업무에서 점점 복잡해지는 빌드 과정이나 직접 만든 툴을 적용하거나 하는 등
좀더 작업을 추가하고 싶을때 불편했습니다.
그래서 앞으로 강좌에도 좀 복잡하지만 Makefile을 계속 쓰는 걸로 해보려고합니다.

다음장부터 Makefile작성이 나오니까요 꼭 봐주세요.
이정도는 차라리 automake+libtool이 낫다 싶으시면 다시 말씀해주시길 부탁드리겠습니다.
저도 고민되는 부분이거든요.
그냥 automake+libtool로 쉽게 설명할 것인가 아니면 Makefile의 매크로나 템플릿을 사용하는
긴 설명을 해야할 것인가 고민됩니다.

김정균의 이미지

2번의 예로 드신 부분은 논란의 여지가 있습니다.

"grep string file" 보다 "cat file | grep string" 이 오버헤드가 적다고 적어주셨지만, 실제 그렇지 않습니다. 대략 100M byte 정도의 파일을 가지고 테스트 해 보시면 전자가 후자보다 오버헤드가 더 크신 것을 알 수가 있습니다. :-) grep이 파일을 읽는 것보다 cat이 파일을 읽는 성능이 더 좋기 때문에 발생하는 문제입니다. :-)

김정균의 이미지

5번의 가정은 치명적입니다. gnu tools가 제공이 되지만 기본이 아닌 경우가 있기 때문이죠. 예를 들어 make만 해도 FreeBSD에서는 gnu make와 호환이 잘 되지 않습니다. gnu make가 extension을 많기 제공하기 때문입니다. 예를 들어

SOURCES = $(wildcard *.c)
OBJS    = $(SOURCES:.c=.o)
 
%.c:
        $(CC) -c $@

이런 extension들이 있으면 문제가 되죠. 이런 호환성 때문에 automake를 사용하게 되는데, gnu tool이라고 가정을 세워 버리면 이런 좋은 장점을 굳이 버리고 automake를 사용하는 것이 더 불편해지는 거죠.

그러므로 autotools를 사용하실 것이라면 타 개발 환경을 고민을 하시는 것이 좋습니다.

저도, redhat 계열에서만 개발을 하다, ubuntu, freebsd 환경에서 사용해야 하는 경우가 발생했는데, 이제껏 autotools를 이용해서 만들어 왔지만, ubutu, freebsd를 위해서 완전히 새로 작업을 하고 있습니다. 할때 제대로 했으면 이렇게 큰 공사가 아니었을텐데 말이죠. 제가 잘못알고 있거나 우물안 개구리 식으로 가진 정보때문에 더 불편하게 된 경우라 이렇게 딴지를 걸어 봅니다.

hongwoo의 이미지

좋은 글 고맙습니다.

그런데.. 저는....
case "${host}" in
i[3-6]86-* )

이게 잘 안먹네요...

case "${host}" in
i386-* | i486-* | i586-* | i686-* )

이렇게 하면.. 의도대로 결과가 나오는데요.
bash에서 인식할 수 있는 정규표현식은 뭔가 다른듯... 하네요.
문제가 뭘까요 ?

-----------------------------
in the real-time scheduler !

hongwoo의 이미지

case "${host}" in
i[[3-6]]86-* )
이렇게 하니 되네요....

오~ http://mywiki.wooledge.org/BashFAQ/031

-----------------------------
in the real-time scheduler !

gurugio의 이미지

아..제가 i386머신이 없어서 테스트를 못했습니다.
3-6으로 수정하겠습니다.

김정균의 이미지

sh가 bash라는 법이 존재를 하지 않습니다. Bsd의 경우 sh는 borne shell이고, ubuntu만 해도 dash입니다. bash라고 생각하고 만드시면 ubuntu 같은 곳에서는 빌드 되지 않습니다. 그러므로 shell syntax는 borne shell 문법을 기준으로 해야 합니다.

예로 들면.. bash에서는

If [ -z "$CC" ]; then
  CC="gcc"
fi

이렇게 하겠지만, configure script에서는 이렇게 하면 엉뚱하게 configure 파일이 생성됩니다.

if test -z "$CC"; then
  CC="gcc"
fi

와 같이 해야 합니다.

hongwoo의 이미지

아.. 제가 글을 제대로 못썼네요.

저기.. [ ] 를 [[ ]] 로.. 하면 됩니다.
double square bracket ... 으로요

글 쓰기는 이렇게 어렵네요.
ㅜㅜ

-----------------------------
in the real-time scheduler !

obbaya의 이미지

차분하게 글을 잘 쓰시네요.

필요했던 내용인데 큰 도움이 되었습니다.

다음 회가 되요!

yo-tteum의 이미지

잘보고 있습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.