Automake使用(中级)

工程地址

automake语言国际化

最初工程目录结构

$ ls -l
total 16
drwxrwxr-x. 2 fedora fedora 4096 May 10 10:38 build-aux
drwxrwxr-x. 2 fedora fedora 4096 May 10 10:38 m4
drwxrwxr-x. 2 fedora fedora 4096 May 10 10:38 po
drwxrwxr-x. 2 fedora fedora 4096 May 10 10:38 src
$ ls -l src/
total 4
-rw-rw-r--. 1 fedora fedora 572 May 10 10:38 main.cpp

源文件剖析

$ cat main.cpp
#include <iostream>
#include <stdio.h>
#include "config.h"
#include "gettext.h"
#define _(String) gettext (String)

int main()
{
    std::cout << PACKAGE << std::endl;
    std::cout << LOCALEDIR << std::endl;
        setlocale(LC_ALL, "");
    std::cout << "===================" << std::endl;
    std::cout << bindtextdomain(PACKAGE, LOCALEDIR) << std::endl;
    std::cout << bind_textdomain_codeset(PACKAGE, "UTF-8") << std::endl;
    std::cout << textdomain(PACKAGE) << std::endl;

    std::cout << _("just test gettext!") << std::endl;
    printf(_("Hello Getext!\n"));
}

可以使用PACKAGE宏

#include "config.h"

使用gettext,使用方式是用 _() 来包含需要参与翻译的字符串

#include "gettext.h"
#define _(String) gettext (String)

LOCALEDIR/LANG/LC_MESSAGE 目录下去寻找消息域 PACKAGE.mo ,指定消息域 PACKAGE 的编码格式为 utf8 ,然后设置当前环境的消息域为 PACKAGE 。注意LINUX环境下 LOCALEDIR 尽量使用绝对路径,因为如果使用相对路径,相对的是命令执行时的路径,而不是可执行文件所在的路径,即如果可执行文件被安装在bin目录下, LOCALEDIR 并不一定是 ./../share/locale ,而且要保持 configure.ac 中定义的的 GETTEXT_PACKAGE 的值和 bindtextdomain/bind_textdomain_codeset/textdomain 所使用的消息域名保持一致

bindtextdomain(PACKAGE, LOCALEDIR)
bind_textdomain_codeset(PACKAGE, "UTF-8")
textdomain(PACKAGE)

将工程改造成automake

运行autoscan

生成configure.scan文件,然后将此文件后缀改为.ac

$ autoscan
$ mv configure.scan configure.ac
$ git add configure.ac
$ git commit -m "autoscan"

修改configure.ac文件

后面autoconf将根据此文件生成最终的configure脚本

$ vim configure.ac
$ git add configure.ac
$ git commit -m "Modify configure.ac"
$ git diff --cached 1c0b2a660b2878f23d287f3ab0b5c93b063c521c
diff --git a/configure.ac b/configure.ac
index efcac1b..dce09b7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,13 +1,66 @@
 #                                               -*- Autoconf -*-
 # Process this file with autoconf to produce a configure script.
 
+# autoconf版本 
 AC_PREREQ([2.69])
-AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
+# 初始化包信息,将会自动生成PACKAGE_NAME、PACKAGE_VERSION、PACKAGE_BUGREPORT宏
+AC_INIT([gettext], [1.0], [fwdssg.love@163.com])
+# 通过检测目录中必定存在的文件来判断目录是否存在
 AC_CONFIG_SRCDIR([src/main.cpp])
+# 生成config.h文件保存configure.ac定义的宏,此文件可被源文件包含
 AC_CONFIG_HEADERS([config.h])
+# 用来存储本地宏文件,.m4的文件都将被保存进此目录,acloacl命令会自动创建此目录
+AC_CONFIG_MACRO_DIRS([m4])
+# 用来存储一些辅助脚本文件
+AC_CONFIG_AUX_DIR([build-aux])
+# 初始化automake
+AM_INIT_AUTOMAKE([subdir-objects -Wno-portability])
+# 初始化gettext
+AM_GNU_GETTEXT([external])
+AM_GNU_GETTEXT_VERSION([0.19.6])
+# 初始化libtool
+IT_PROG_INTLTOOL([0.35.0])
+
+# 标准的平台检测脚本,将生成WIXL_ARCH和OS_WIN32宏,可在Makefile.am中使用
+AC_MSG_CHECKING([for native Win32])
+case "$host_os" in
+     *mingw*|*cygwin*)
+        os_win32=yes
+        case "$host" in
+            amd64*|x86_64*)
+                WIXL_ARCH="x64"
+            ;;
+            *)
+                WIXL_ARCH="x86"
+            ;;
+        esac
+        AC_SUBST(WIXL_ARCH)
+        ;;
+     *)
+        os_win32=no
+        ;;
+esac
+AC_MSG_RESULT([$os_win32])
+AM_CONDITIONAL([OS_WIN32],[test "$os_win32" = "yes"])
+
+# windows下资源生成工具检测(此项目非必须,仅做演示)
+AS_IF([test "x$os_win32" = "xyes"], [
+     AC_CHECK_TOOL(WINDRES, [windres])
+
+     if test -z "$WINDRES" ; then
+       AC_MSG_ERROR("windres is required to compile tropolink-gtk on this platform")
+     fi
+])
 
 # Checks for programs.
 AC_PROG_CXX
+# 初始化要连接的obj目录
+AC_CONFIG_LIBOBJ_DIR([src])
+
+# 初始化mo文件名,也是bindtextdomain搜索时候的domainname
+GETTEXT_PACKAGE=$PACKAGE
+AC_SUBST(GETTEXT_PACKAGE)
+AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE],"$GETTEXT_PACKAGE", [GETTEXT package name])
 
 # Checks for libraries.
 
@@ -18,4 +71,9 @@ AC_PROG_CXX
 # Checks for library functions.
 AC_CHECK_FUNCS([setlocale])
 
+# 设置运行configure后需要生成的文件,需要编写对应的.in文件,即需要生成Makefile,则必须存在Makefile.in文件,它们将被config.status使用用来生成Makefile
+AC_CONFIG_FILES([ 
+    Makefile
+    src/Makefile
+])
 AC_OUTPUT

运行libtoolize

生成libtool相关辅助文件,ltmain.sh和libtool.m4等宏文件

$ libtoolize
$ git status
$ git add --all
$ git commit -m "libtoolize"

运行gettextize

生成国际化所需相关文件

$ gettextize
$ git status
$ git diff configure.ac
diff --git a/configure.ac b/configure.ac
index dce09b7..a5b16a8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,7 +17,7 @@ AC_CONFIG_AUX_DIR([build-aux])
 AM_INIT_AUTOMAKE([subdir-objects -Wno-portability])
 # 初始化gettext
 AM_GNU_GETTEXT([external])
-AM_GNU_GETTEXT_VERSION([0.19.6])
+AM_GNU_GETTEXT_VERSION([0.19.7])
 # 初始化libtool
 IT_PROG_INTLTOOL([0.35.0])
 
@@ -72,7 +72,7 @@ AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE],"$GETTEXT_PACKAGE", [GETTEXT package name])
 AC_CHECK_FUNCS([setlocale])
 
 # 设置运行configure后需要生成的文件,需要编写对应的.in文件,即需要生成Makefile,则必须存在Makefile.in文件,它们将被config.status使用用来生成Makefile
-AC_CONFIG_FILES([ 
+AC_CONFIG_FILES([  po/Makefile.in
     Makefile
     src/Makefile
 ])
$ rm -rf configure.ac~
$ git add --all
$ git commit -m

运行aclocal

生成autoconf所需的宏文件aclocal.m4

$ aclocal
$ git status
$ git add aclocal.m4
$ git commit -m "aclocal.m4"

运行autoconf

根据configure.ac生成configure脚本

$ autoconf
$ git status
$ git add configure
$ git commit -m "autoconf"

运行autoheader

生成 config.h.in 文件,用于生成 config.h 文件,此文件保存了configure.ac中定义的宏,可被程序使用

$ autoheader
$ git status
$ git add config.h.in
$ git commit -m "autoheader"

编写Makefile.am

Makefile.am注解
作用
SUBDIRS 存在Makefile.am的子目录
DISTCLEANFILES 执行 make distclean 要被删除的文件
MAINTAINERCLEANFILES 执行 make maintainer-clean 要被删除的文件
dist-hook 执行 make dist 时将被调用的命令
EXTRA_DIST 不会被编译,但是执行 make dist 又需要被打包的文件
bin_PROGRAMS 编译生成的可执行文件名
XX_LDADD 需要链接一些特殊的obj或者库文件,例如由.rc生成的.o文件
XX_CPPFLAGS -I -D 之类的编译参数
XX_LDFLAGS -L 之类的链接参数
_LTLIBRARIES 生成libtool库
XX_la_LIBADD 生成libtool库需要链接的文件
XX_LDFLAGS 生成libtool库的链接参数
顶层目录的Makefile.am
  • Makefile.ambuild-aux/gitlog-to-changelog 以及 AUTHORS.in 取自 Virt Viewer ,可以当做模板来使用
  • 一般情况下我们只需要根据 configure.acAC_CONFIG_FILES 来修改 Makefile.am 模板的 SUBDIRS 来决定需要生成Makefile的子目录,每个Makefile.am只需要包含子目录即可,如果有嵌套目录需要生成Makefile,则在子目录的Makefile.am设置 SUBDIRS
$ cat Makefile.am
NULL =

ACLOCAL_AMFLAGS = -I m4

SUBDIRS = src po

INTLTOOL_FILES =                \
    intltool-extract.in            \
    intltool-merge.in            \
    intltool-update.in            \
    $(NULL)

DISTCLEANFILES =                \
    intltool-extract            \
    intltool-merge                \
    intltool-update                \
    $(NULL)

EXTRA_DIST = build-aux/config.rpath                     \
    $(INTLTOOL_FILES)            \
    build-aux/gitlog-to-changelog        \
    AUTHORS.in                \
    autogen.sh                \
    $(NULL)

MAINTAINERCLEANFILES =                \
    aclocal.m4                \
    config.h.in                \
    m4/intltool.m4                \
    m4/libtool.m4                \
    m4/ltoptions.m4                \
    m4/ltsugar.m4                \
    m4/ltversion.m4                \
    m4/lt~obsolete.m4            \
    build-aux/ar-lib            \
    build-aux/compile            \
    build-aux/config.guess            \
    build-aux/config.rpath            \
    build-aux/config.sub            \
    build-aux/depcomp            \
    build-aux/install-sh            \
    build-aux/ltmain.sh            \
    build-aux/missing            \
    po/Makefile.in.in            \
    $(NULL)

DISTCLEAN_FILES =                \
    intltool-extract            \
    intltool-merge                \
    intltool-update                \
    $(NULL)

dist-hook: gen-ChangeLog gen-AUTHORS

# Generate the ChangeLog file (with all entries since the switch to git)
# and insert it into the directory we're about to use to create a tarball.

.PHONY: gen-ChangeLog gen-AUTHORS

gen-ChangeLog:
    if test -d .git || test -d ../.git; then        \
      $(top_srcdir)/build-aux/gitlog-to-changelog        \
        > $(distdir)/cl-t;                    \
      rm -f $(distdir)/ChangeLog;                \
      mv $(distdir)/cl-t $(distdir)/ChangeLog;        \
    fi

gen-AUTHORS:
    $(AM_V_GEN)if test -d $(srcdir)/.git; then                      \
       out="`cd $(srcdir) && git log --pretty=format:'%aN <%aE>' | sort -u`" && \
       perl -p -e "s/#authorslist#// and print '$$out'"            \
         < $(srcdir)/AUTHORS.in > $(distdir)/AUTHORS-tmp &&        \
       mv -f $(distdir)/AUTHORS-tmp $(distdir)/AUTHORS ;           \
    fi

$ git status
$ git add AUTHORS.in Makefile.am build-aux/gitlog-to-changelog
$ git commit -m "Top Makefile.am"
src目录的Makefile.am
$ cat Makefile.am
NULL =

bin_PROGRAMS = Gettext
Gettext_LDADD =

#
#Gettext_CPPFLAGS = \
#    -DLOCALEDIR="\"./../share/locale\"" \
#    $(NULL)

Gettext_CPPFLAGS = \
    -DLOCALEDIR="\"$(localedir)\"" \
    $(NULL)

Gettext_CXXFLAGS = -ggdb3 -Wall -MMD  -fpermissive -g
MAINTAINERCLEANFILES =

COMMON_LIBS = \
    -lm                    \
    $(NULL)

COMMON_CPPFLAGS = \
    $(NULL)

Gettext_SOURCES = \
        main.cpp                                \
        gettext.h                \
        $(NULL)

Gettext_LDFLAGS = \
    $(COMMON_LIBS)                \
    $(NULL)

Gettext_CPPFLAGS += \
    $(COMMON_CPPFLAGS)             \
    $(NULL)

$ git status
$ git add src/Makefile.am
$ git commit -m 'src/Makefile.am'

创建automake必要文件

COPYING 文件可以从一些开源项目下面复制过来,其他文件使用 touch 命令生成

$ git status
$ git add AUTHORS COPYING NEWS README
$ git commit -m "Necessery Files"

运行automake

生成 Makefile.in 文件

$ automake -a
$ git status
$ git add INSTALL Makefile.in build-aux/compile build-aux/config.guess build-aux/config.sub build-aux/depcomp build-aux/install-sh build-aux/missing src/Makefile.in
$ git commit -m "automake"

编辑po/POTFILES.in文件

填入需要进行国际化字符转换的源文件,即包含文件中包含 _() 的源文件

$ vim POTFILES.in
$ git add POTFILES.in
$ git commit -m "Modify POTFILES.in"
$ git diff --cached 3b7860256a9c58f68bbee285dd65d18905796247
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 667e27c..1bc579b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1 +1,3 @@
 # List of source files which contain translatable strings.
+
+src/main.cpp

执行autogen.sh

  • autogen.sh 取自 Virt Viewer ,可以当做模板来使用
  • 根据实际情况修改 echo "Now type 'make' to compile Gettext." 即可
$ cat autogen.sh
#!/bin/sh
# Run this to generate all the initial makefiles, etc.

set -e

srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.

THEDIR=`pwd`
cd $srcdir

EXTRA_ARGS=""
if test "x$1" = "x--system"; then
    shift
    prefix=/usr
    libdir=$prefix/lib
    sysconfdir=/etc
    localstatedir=/var
    if [ -d /usr/lib64 ]; then
        libdir=$prefix/lib64
    fi
    EXTRA_ARGS="--prefix=$prefix --sysconfdir=$sysconfdir --localstatedir=$localstatedir --libdir=$libdir"
fi

# Real ChangeLog/AUTHORS is auto-generated from GIT logs at
# make dist time, but automake requires that it
# exists at all times :-(
touch ChangeLog AUTHORS

mkdir -p m4
autoreconf -vfi
intltoolize --force

cd $THEDIR

if [ -z "$NOCONFIGURE" ]; then
    if test -z "$*" ; then
        echo "I am going to run ./configure with no arguments - if you wish "
        echo "to pass any to it, please specify them on the $0 command line."
    fi
    $srcdir/configure $EXTRA_ARGS "$@" && {
        echo
        echo "Now type 'make' to compile Gettext."
    }
fi

$ git add autogen.sh
$ git commit -m "Add autogen.sh"

生成po文件

  • 执行 make -C po/ update-po 生成程序对应的POT文件 gettext.pot
  • 在po目录下执行 msginit --locale zh_CN.utf8 生成对应语言的PO文件
  • 编辑PO文件完成翻译
  • 创建 LINGUAS 文件,并填入PO文件中的"Language"属性
$ make -C po/ update-po
$ cd po/
$ msginit --locale zh_CN.utf8
$ msginit --locale en_US.utf8
$ vim zh_CN.po
$ vim en_US.po
$ touch LINGUAS
$ vim LINGUAS
$ cat LINGUAS
zh_CN en_US

运行make

  • 拷贝gettext.h文件到src目录
$ sudo find / -name gettext.h 2>/dev/null
$ cp /usr/share/gettext/gettext.h src/
$ make

测试Gettext

$ LANG=en_US src/Gettext
gettext
/usr/local/share/locale
===================
/usr/local/share/locale
UTF-8
gettext
Amarican Gettext!
Amarican Hello!
$ LANG=zh_CN src/Gettext
gettext
/usr/local/share/locale
===================
/usr/local/share/locale
UTF-8
gettext
Chinese gettext!
Chinese Hello!
posted @ 2017-10-14 10:33  银魔术师  阅读(962)  评论(0编辑  收藏  举报