GNU M4
- GNU 에서 만든 고전적인 유닉스 매크로 프로세서
- m4-*/examples 에 GNU M4 로 만든 예제가 있으며, 예제의 대부분은 솔라리스 m4 에서도 실행할 수 있다. 이 예제파일은 설치되지 않는다. M4에 대한 사항은 윈디하나의 솔라나라: M4, GNU M4을 읽어보자.
- 공식홈페이지: GNU M4
소스 설치
# wget https://ftp.gnu.org/gnu/m4/m4-1.4.18.tar.xz
# tar xvfJ m4-1.4.18.tar.xz
# cd m4-1.4.18
# ./configure CFLAGS="-m64" LDFLAGS="-m64"
# make
# sudo make install
솔라리스 11 패키지 설치
# pkg install gnu-m4
# gm4 --version
m4 (GNU M4) 1.4.12
-
소스 설치
windy@wl ~/src $ wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
windy@wl ~/src $ tar xvfz autoconf-2.69.tar.gz
windy@wl ~/src $ cd autoconf-2.69
windy@wl ~/src/autoconf-2.69 $ ./configure
windy@wl ~/src/autoconf-2.69 $ make
windy@wl ~/src/autoconf-2.69 $ sudo make install
패키지 설치(솔라리스 11 이상)
windy@wl ~ $ sudo pkg install autoconf
windy@wl ~ $ autoconf --version
autoconf (GNU Autoconf) 2.68
-
소스 설치
windy@wl ~/src $ wget http://ftp.gnu.org/gnu/automake/automake-1.16.1.tar.xz
windy@wl ~/src $ tar xvfJ automake-1.16.1.tar.xz
windy@wl ~/src $ cd automake-1.16.1
windy@wl ~/src/automake-1.16.1 $ ./configure CFLAGS="-m64" LDFLAGS="-m64"
windy@wl ~/src/automake-1.16.1 $ make
windy@wl ~/src/automake-1.16.1 $ sudo make install
패키지 설치(솔라리스 11 이상)
windy@wl ~ $ sudo pkg install automake
windy@wl ~ $ automake --version
automake (GNU automake) 1.11.2
-
Autoconf Archive는 500여가지의 Autoconf용 매크로의 모음이다. 인터넷에서 공헌자들에 의해 개발되고 지원되는 매크로들이지만, 사실상 Autoconf의 공식적이라 할 만큼 잘 만들어져 있다. 매크로의 목록은 Autoconf Archive - The Macros를 참고하자.
windy@wl ~/src $ wget http://ftp.jaist.ac.jp/pub/GNU/autoconf-archive/autoconf-archive-2019.01.06.tar.xz
windy@wl ~/src $ cd autoconf-archive-2019.01.06
windy@wl ~/src/autoconf-archive-2019.01.06 $ ./configure
windy@wl ~/src/autoconf-archive-2019.01.06 $ make
windy@wl ~/src/autoconf-archive-2019.01.06 $ sudo make install
-
Texinfo는 GNU 프로젝트의 공식적인 문서 시스템이다.
info
문서를 생성할 때 필요한 라이브러리다.
windy@wl ~/src $ wget http://ftp.gnu.org/gnu/texinfo/texinfo-6.1.tar.xz
windy@wl ~/src $ tar xvfJ texinfo-6.1.tar.xz
windy@wl ~/src $ cd texinfo-6.1
windy@wl ~/src/texinfo-6.1 $ ./configure
windy@wl ~/src/texinfo-6.1 $ make
windy@wl ~/src/texinfo-6.1 $ make install
-
소스설치
windy@wl ~/src $ wget http://mirror.yongbok.net/gnu/libtool/libtool-2.4.6.tar.xz
windy@wl ~/src $ tar xvfJ libtool-2.4.6.tar.xz
windy@wl ~/src $ cd libtool-2.4.6
windy@wl ~/src/libtool-2.4.6 $ ./configure CFLAGS="-m64" LDFLAGS="-m64"
windy@wl ~/src/libtool-2.4.6 $ make
windy@wl ~/src/libtool-2.4.6 $ sudo make install
패키지 설치(솔라리스 11 이상)
windy@wl ~ $ sudo pkg install pkg:/developer/build/libtool
windy@wl ~ $ libtool --version
libtool (GNU libtool) 2.4.6
...
-
예제는
Hello World!
를 출력하는 C프로그램이다. helloworld.c
, helloworld.h
, main.c
의 세개의 소스파일로 구성되어있다. helloworld.c
, helloworld.h
으로 libhelloworld.so
를 빌드하고, main.c
에서 로드해 사용한다.
#include "helloworld.h"
int main(int argc, char *argv[]) {
print_helloworld();
print_offtsize();
}
#ifndef helloworld_h
#define helloworld_h
#ifdef __cplusplus
extern "C" {
#endif
void print_helloworld();
void print_offtsize();
#ifdef __cplusplus
}
#endif
#endif
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "helloworld.h"
#include <stdio.h>
void print_helloworld() {
#ifdef EXTRAMESSAGE
printf("Hello, World! %s\n", EXTRAMESSAGE);
#else
printf("Hello, World!\n");
#endif
}
void print_offtsize() {
printf("off_t size is %d bytes.\n", sizeof(off_t));
}
windy@wl ~/autotools/src $ wget http://www.solanara.net/contents/includes/autotools/main.c
windy@wl ~/autotools/src $ wget http://www.solanara.net/contents/includes/autotools/helloworld.h
windy@wl ~/autotools/src $ wget http://www.solanara.net/contents/includes/autotools/helloworld.c
빌드는 아래와 같이 할 수 있다. 테스트한 후 helloworld 는 삭제한다.
windy@wl ~/autotools/src $ cc -o helloworld main.c helloworld.c
windy@wl ~/autotools/src $ ./helloworld
Hello, World!
off_t size is 4 bytes.
windy@wl ~/autotools/src $ rm helloworld
-
Automake 용 Makefile.am 을 만든다. Makefile 을 만들기 위함이다.
windy@wl ~/autotools $ vi Makefile.am
AUTOMAKE_OPTIONS = foreign
SUBDIRS = src
ACLOCAL_AMFLAGS = -I m4
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = helloworld.pc
windy@wl ~/autotools $ vi src/Makefile.am
ACLOCAL_AMFLAGS = -I m4
AM_CFLAGS = -O3
AM_LDFLAGS =
bin_PROGRAMS = helloworld
sbin_PROGRAMS = helloworld
helloworld_SOURCES = main.c
helloworld_LDADD = libhelloworld.la
lib_LTLIBRARIES = libhelloworld.la
libhelloworld_la_SOURCES = helloworld.c helloworld.h
libhelloworld_la_LDFLAGS = -version-info $(LIBHELLOWORLD_LIBRARY_VERSION) -release $(LIBHELLOWORLD_RELEASE_VERSION)
여기까지 하면 아래와 같이 파일이 있어야 한다.
windy@wl ~/autotools $ find . | sort
./
./Makefile.am
./src
./src/helloworld.c
./src/main.c
./src/helloworld.h
./src/Makefile.am
-
Autoconf용 configure.ac 파일을 만든다. 이 파일에는 시스템에서 빌드를 하기 위해 어떤 사항을 검사해야 하는지, 빌드를 위한 옵션으로 어떤것이 있는지 명시한다. 즉 configure.ac
는 configure
스크립트를 만들기 위해 필요한 매크로를 정의한다.
예를 들어 시스템에서 컴파일러로 gcc(1)와 cc(1) 중 어떤 컴파일러를 사용하는지 알아내서 각각에 맞는 컴파일 플래그를 지정하는 매크로를 정의하거나, 컴파일에 반드시 필요한 라이브러리가 있는 경우 라이브러리가 미리 인스톨 되어있는지 검사할 수 있는 매크로를 정의할 수 있다. 자주 사용되는 매크로의 경우 미리 만들어 놓은 것도 있다. 예를 들어 시스템이 2GB이상 파일을 읽고 쓸 수 있는지 알려면 AC_SYS_LARGEFILE
매크로를 넣어주기만 하면 된다. 미리 정의된 테스트의 목록은 Autoconf - 5 Existing Tests을 참고하자.
아래는 Hello World! 프로그램에서 사용할 configure.ac 를 만드는 방법에 대해 소개한다.
windy@wl ~/autotools $ autoscan 1)
windy@wl ~/autotools $ cp configure.scan configure.ac
windy@wl ~/autotools $ vi configure.ac
AC_INIT(helloworld, 1.0, admin@solanara.net) 2)
AC_CONFIG_FILES([helloworld.pc])
AC_USE_SYSTEM_EXTENSIONS
AC_SYS_LARGEFILE
AM_INIT_AUTOMAKE
LT_INIT
AM_SILENT_RULES([yes])
AH_TOP([#ifndef AUTO_CONFIG_H
#define AUTO_CONFIG_H
])
AH_BOTTOM([
#endif /*AUTO CONFIG H */
])
LIBHELLOWORLD_RELEASE_VERSION=1
LIBHELLOWORLD_LIBRARY_VERSION=1:0:0
AC_SUBST(LIBHELLOWORLD_RELEASE_VERSION)
AC_SUBST(LIBHELLOWORLD_LIBRARY_VERSION)
AX_LIB_SOCKET_NSL
AC_ARG_ENABLE([32-bit], [AS_HELP_STRING([--enable-32-bit],[Build 32bit Library])], [CFLAGS="$CFLAGS -m32"; LDFLAGS="$LDFLAGS -m32"])
AC_ARG_ENABLE([64-bit], [AS_HELP_STRING([--enable-64-bit],[Build 64bit Library])], [CFLAGS="$CFLAGS -m64"; LDFLAGS="$LDFLAGS -m64"])
AC_ARG_WITH([extramessage],[AS_HELP_STRING([--with-extramessage],[Print with extra message])], [AC_DEFINE_UNQUOTED(EXTRAMESSAGE, ["$withval"], [Print Extra Message])])
AC_CONFIG_MACRO_DIR([m4])
root@wl ~/autotools # ifnames src/* 3)
EXTRAMESSAGE src/helloworld.c
HAVE_CONFIG_H src/helloworld.c
__cplusplus src/helloworld.h
helloworld_h src/helloworld.h
1) configure.scan, autoscan.log 파일이 생성된다. autoscan.log 파일은 지워도 된다. autoscan을 하지 않고 configure.ac를 직접 만들어도 되지만, 이 예제에서는 autoscan에 의해 생성되는 스크립트는 제외하고 보여준다.
2) AC_INIT 부분을 수정한다. 나머지 스크립트는 AC_OUTPUT 위의 적당한 위치에 추가한다. 스크립트중 AC_SYS_LARGEFILE, AC_USE_SYSTEM_EXTENSIONS, AX_LIB_SOCKET_NSL 은 helloworld 프로그램과는 관련 없다. 예제를 보이기 위해 넣었을 뿐이다. AX_LIB_SOCKET_NSL 은 Autoconf Archive를 설치해야 사용할 수 있다.
3) 소스를 읽어 #if, #elif, #ifdef, #ifndef, ... 등에 사용된 지시자를 표시해준다. configure.ac 에 필요한 옵션들이 모두 등록했는지 확인하기 위함이다.
-
pkg-config(1)를 지원하려면, helloworld.pc를 생성해야 하며, 이를 생성하고 설치하려면 helloworld.pc.in 을 만들어야 한다. .pc 파일에 대해서는 pkg-config(1)을 참조하자. (Makefile.am, configure.ac 파일에 이미 pkg-config 용 설정이 추가되어있다)
windy@wl ~/autotools $ vi helloworld.pc.in 1)
prefix=@prefix@
exec_prefix=@exec_prefix@
includedir=@includedir@
libdir=@libdir@
Name: LibHelloWorld
Description: Helloworld Library
URL: http://www.solanara.net/solanara/autotools
Version: @PACKAGE_VERSION@
Cflags: -I${includedir}
Libs: -L${libdir} -lhelloworld
Libs.private:
configure.ac
여기까지 작업했다면 사실상 배포판을 위한 모든 작업을 마친 셈이다. 아래부터는 어느 프로젝트에서나 같은 명령을 사용한다. 여기까지 작업한 파일은
autotools.tar.gz에서 받을 수 있다.
-
이제 configure 를 만들기 위한 마지막 단계다. 아래와 같이 프로그램을 차례대로 실행해주면 작업은 완료된다.
windy@wl ~/autotools $ libtoolize 1)
libtoolize: putting auxiliary files in `.'.
libtoolize: linking file `./ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIR, `m4'.
libtoolize: linking file `m4/libtool.m4'
libtoolize: linking file `m4/ltoptions.m4'
libtoolize: linking file `m4/ltsugar.m4'
libtoolize: linking file `m4/ltversion.m4'
libtoolize: linking file `m4/lt~obsolete.m4'
windy@wl ~/autotools $ cp /usr/local/share/aclocal/ax_lib_socket_nsl.m4 ./m4/
windy@wl ~/autotools $ aclocal 2)
windy@wl ~/autotools $ autoheader 3)
windy@wl ~/autotools $ automake --add-missing 4)
configure.ac:8: installing './compile'
configure.ac:12: installing './config.guess'
configure.ac:12: installing './config.sub'
configure.ac:11: installing './install-sh'
configure.ac:11: installing './missing'
src/Makefile.am: installing './depcomp'
windy@wl ~/autotools $ autoconf 5)
1) m4
디렉토리를 생성하고, ltmain.sh
파일을 링크한다.
2) aclocal.m4
파일을 생성한다. autom4te.cache
디렉토리에도 몇개의 캐시 파일을 생성한다.
3) config.h.in
파일을 생성한다.
4) Makefile.in
파일을 생성하고, compile
, config.guess
, config.sub
, install-sh
, missing
, depcomp
를 링크한다.
5) configure
파일을 생성한다.
autoreconf
configure.ac 가 갱신되었다면 autoheader 부터 autoconf 까지의 명령어를 일일이 실행해야 하는데,
autoreconf(1)는 이 과정을 한번에 해준다.
-
configure 스크립트가 생성되었으면 아래와 같이 테스트해본다.
windy@wl ~/autotools $ ./configure --prefix=/usr/local/hw --enable-64-bit --with-extramessage="SOLANARA"
windy@wl ~/autotools $ make
windy@wl ~/autotools $ sudo make install
windy@wl ~/autotools $ cd /usr/local/hw
windy@wl /usr/local/hw $ find .
.
./lib
./lib/libhelloworld.so
./lib/libhelloworld.a
./lib/libhelloworld.la
./lib/pkgconfig
./lib/pkgconfig/helloworld.pc
./lib/libhelloworld-1.so.1.0.0
./lib/libhelloworld-1.so.1
./bin
./bin/helloworld
./sbin
./sbin/helloworld
windy@wl /usr/local/hw $ ./bin/helloworld
Hello, World! SOLANARA
windy@wl /usr/local/hw $ ldd ./bin/helloworld
libhelloworld-1.so.1 => /usr/local/hw/lib/libhelloworld-1.so.1
libsocket.so.1 => /lib/64/libsocket.so.1
libnsl.so.1 => /lib/64/libnsl.so.1
libc.so.1 => /lib/64/libc.so.1
libmp.so.2 => /lib/64/libmp.so.2
libucrypto.so.1 => /lib/64/libucrypto.so.1
libelf.so.1 => /lib/64/libelf.so.1
libcryptoutil.so.1 => /lib/64/libcryptoutil.so.1
libz.so.1 => /lib/64/libz.so.1
-
아래와같이 배포본을 만들 수 있다. 이 작업을 하기 전에 configure 를 한번 실행시켜야 한다.
root@wl ~/autotools # make dist
root@wl ~/autotools # make dist-bzip2
root@wl ~/autotools # make dist-lzip 1)
root@wl ~/autotools # make dist-xz 1)
root@wl ~/autotools # ls -alh *.tar.*
-rw-r--r-- 1 windy staff 247K 6월 17일 00:00 helloworld-1.0.tar.bz2
-rw-r--r-- 1 windy staff 304K 6월 17일 00:00 helloworld-1.0.tar.gz
-rw-r--r-- 1 windy staff 204K 6월 17일 00:00 helloworld-1.0.tar.lz
-rw-r--r-- 1 windy staff 204K 6월 17일 00:00 helloworld-1.0.tar.xz
root@wl ~/autotools #
1) xz, lzip 파일이 필요하다. 설치방법은 윈디하나의 솔라나라: 아카이버 및 컴프레서를 읽어보자.
-
automake(1) 가 기본적으로 생성하는 make 의 타겟에 대해 설명한다. 흔히 사용하는건
all
, install
, clean
이지만 이외의 타겟에 대해서도 설명한다.
all
: 모든 프로그램 컴파일
install
: 모든 프로그램 컴파일 후 지정한 디렉토리에 복사
install-html
, install-dvi
, install-pdf
, install-ps
: 문서 복사
uninstall
: install* 에 의해 설치한 파일 삭제
install-strip
: 실행 가능한 파일을 strip(1) 한 후 복사. 이외에는 install
과 동일
clean
: 빌드하기 위해 생성한 파일을 삭제(컴파일된 오브젝트 파일, 실행파일등)
distclean
: 설정 및 빌드를 위해 생성한 파일을 삭제(clean 및 Makefile 포함)
mostlyclean
: clean과 비슷하지만 라이브러리는 삭제하지 않음
maintainer-clean
: Makefile에 의해 생성된 거의 모든 파일을 삭제. bison의 결과물 포함
TAGS
: 태그 테이블 업데이트
info
: texinfo 를 사용해 info 파일 생성
dvi
, html
, pdf
, ps
: 지정한 형식의 문서를 생성
dist
: 배포판을 만듬
check
: 셀프 테스트를 수행
installcheck
: 설치를 위한 테스트를 실행
installdirs
: 설치를 위한 디렉토리를 생성
더 자세한 사항은 7.2.6 Standard Targets for Users를 읽어보자.
- diff 는 두 파일을 비교해, 소스 파일을 타겟 파일로 변환할 때 필요한 정보를 출력하는 명령이다. patch는 diff 의 결과를 이용해 특정 텍스트 파일을 패치할 수 있도록 하는 명령이다. 프로그램의 소스를 패치할 때 주로 사용된다. 최근의 diff는 바이너리 파일까지 비교할 수 있지만 솔라리스의 diff 는 바이너리를 지원하지 않는다.
-
old.c 를 new.c 로 바꿨다. 두 파일의 차이를 알아내 패치 파일을 만든 후, old.c 와 동일한 내용의 hello.c를 패치해 new.c 와 동일한 내용을 가지게 하도록 할 것이다.
root@wl ~ # cat new.c
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello, World!\n");
}
root@wl ~ # cat old.c
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello, World!");
}
root@wl ~ # cp old.c helloworld.c
root@wl ~ # diff -u old.c new.c > patch.diff 1)
root@wl ~ # cat patch.diff
--- old.c Thu Jul 22 18:14:31 2010
+++ new.c Thu Jul 22 18:14:23 2010
@@ -1,5 +1,5 @@
#include <stdio.h>
int main(int argc, char *argv[]) {
- printf("Hello, World!");
+ printf("Hello, World!\n");
}
root@wl ~ # patch -b -i patch.diff helloworld.c 2)
통합된 문맥 diff처럼 보입니다.
완료
root@wl ~ # ls -l
-rw-r--r-- 1 windy staff 85 7월 22일 18:19 helloworld.c
-rw-r--r-- 1 windy staff 83 7월 22일 18:18 helloworld.c.orig
-rw-r--r-- 1 windy staff 85 7월 22일 18:14 new.c
-rw-r--r-- 1 windy staff 83 7월 22일 18:14 old.c
-rw-r--r-- 1 windy staff 203 7월 22일 18:15 patch.diff
root@wl ~ # cat helloworld.c
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello, World!\n");
}
root@wl ~ #
1) old.c 와 new.c 의 차이를 나타내는 파일을 생성해 patch.diff 로 저장한다. -u 는 출력 형식을 지정하는 것으로 Unified Context형식을 의미한다.
2) -b 는 백업파일 (.orig)을 만들고, -i 는 패치 파일(diff 명령의 결과)의 이름을 정해준다.
-
diff 에는 여러가지 출력 형식이 있다. -c 를 붙여 Context 형식을 사용할 수 있고, -u 를 붙여 Unified Context 형식을 사용할 수 있다. 패치 프로그램에서는 주로 Unified Context 형식을 사용한다.
root@wl ~ # diff old.c new.c
4c4
< printf("Hello, World!");
---
> printf("Hello, World!\n");
root@wl ~ # diff -c old.c new.c
*** old.c Thu Jul 22 18:14:31 2010
--- new.c Thu Jul 22 18:14:23 2010
***************
*** 1,5 ****
#include <stdio.h>
int main(int argc, char *argv[]) {
! printf("Hello, World!");
}
--- 1,5 ----
#include <stdio.h>
int main(int argc, char *argv[]) {
! printf("Hello, World!\n");
}
root@wl ~ # diff -u old.c new.c
*** old.c Thu Jul 22 18:14:31 2010
--- new.c Thu Jul 22 18:14:23 2010
@@ -1,5 +1,5 @@
#include <stdio.h>
int main(int argc, char *argv[]) {
- printf("Hello, World!");
+ printf("Hello, World!\n");
}