Directory structure of a GNU project — Fr 25 April 2025

关于 GNU 工程

你好,世界!

GNU 是唯一一个为用户自由而开发的计算机系统。GNU 项目尊重计算机用户的自由。

你可能是一个 GNU 用户而你却不知道,因为大多数人错误地把 GNU 系统叫做 Linux,而 Linux 只是 GNU 系统的一个内核。

一个软件项目如果要成为 GNU 的软件包需要满足一定的要求,本文简单介绍一下 GNU 软件包的目录结构。

GNU autotools

GNU 软件项目提供软件的源代码和编译系统,让用户可以自主构建二进制可执行文件。

大多数 GNU 软件项目的构建会使用 GNU autotools。autotools 主要是指 GNU autoconf 和 GNU automake,它们使软件编译和构建变得比较统一和明确。一般来说,用户下载 GNU 项目的文件包之后,只需在命令行运行命令,即可编译安装好 GNU 软件:


./configure
make && sudo make install
 

要达到这样的效果,GNU 项目对软件项目的目录结构就有一定的要求。我们来看一看。

GNU 软件项目的目录结构

一个极简的 GNU 软件项目的目录如下:


.
├── AUTHORS          # a list of authors and emails
├── NEWS             # release news
├── README           # readme file
├── ChangeLog        # a list of commit log
├── Makefile.am      # Automake file used to generate the Makefile.in which configure will configure
├── configure.ac     # a template file which Autoconf uses to generate the familiar configure script
├── src              # a folder for source code files
 

这些是一个 GNU 项目必须有的最小目录结构和文件。通常,一个成熟的 GNU 软件项目会有更多的目录结构和文件,比如以一个 GNU Guile 项目为例:


.
├── AUTHORS          # a list of authors and emails
├── COPYING          # AGPL or GPL
├── COPYING.LESSER   # LGPL if used
├── HACKING          # a note for how to hack the program
├── HISTORY          # a history file
├── INSTALL          # installation instructions
├── NEWS             # release news
├── README           # readme file
├── THANKS           # thank you file
├── TODO             # a note for future tasks
├── ChangeLog        # a list of commit log
├── Makefile.am      # Automake file used to generate the Makefile.in which configure will configure
├── a.desktop        # desktop file for the project
├── a.160x160.xpm    # desktop icon file for the project
├── assets           # project assets (e.g. images) folder
├── autogen.sh       # automatic bootstrap all, if bootstrap file is missing
├── bootstrap        # a simple shell script which a developer can regenerate all the GNU Build System files
├── bin              # final bin output folder
├── build-aux        # a folder for build the program: doc, tests, etc
│       └─ pre-inst-env.in  # a shell script which set up environment variables to be able to use your code before installing it
├── configure.ac     # a template file which Autoconf uses to generate the familiar configure script
├── doc              # final doc output folder
├── m4               # a folder for m4 macros - yes
│   └── guile.m4     # a recent copy of Guile's m4 macros
│   └── aclocal.m4   # a possible copy of Guile's m4 macros
├── po               # a folder for project po files
├── src              # a folder for source code files
│   └─ skeleton.scm  # some initial source code file - Guile module (skeleton)
├── src/skeleton
│     └─ hello.scm   # some initial source code file - (skeleton hello) module
└── tests            # a folder for test files
       └─ cases-hello.scm    # some basic tests for hello.scm
 

其中有几个文件相对比较标准,开发者可以参考。比如 'bootstrap' 或 'autogen.sh' 的内容简单为:


#!/bin/sh
# Usage: sh -x ./bootstrap [--libtoolize]

[ -f src/skeleton.scm ] || {
  echo "bootstrap: run this command only in the project directory."
  exit 1
}

set -e -x

######################################################################
# Invoke the auto* tools.

autoreconf -B `guile-config info datadir`/aclocal -v -i -f

######################################################################
# Done.

: Now run configure and make.

# bootstrap ends here
 

'configure.ac' 最少需要包含以下内容:


# program name=helloworld; version=0.1; maintainer=wxie@email
AC_INIT([helloworld], [0.1], [wxie@email])

# use automake
AM_INIT_AUTOMAKE

## use Guile compiler
# We require pkg.m4 (from pkg-config) and guile.m4 (from Guile.)
# Make sure they are available when generating the configure script.
m4_pattern_forbid([^PKG_PROG])
m4_pattern_forbid([^PKG_CHECK])
m4_pattern_forbid([^GUILE_P])
m4_pattern_allow([^GUILE_PKG_ERRORS])
m4_pattern_allow([^GUILE_PKG])
m4_pattern_allow([^GUILE_PROGS])

# Check for latest Guile development files.
# PKG_CHECK_MODULES([GUILE], [guile-3.0])
GUILE_PKG([3.0 2.2])

# Checks for programs.
GUILE_PROGS
GUILE_FLAGS
if test "x$GUILD" = "x"; then
   AC_MSG_ERROR(['guild' binary not found; please check your guile installation.])
fi

dnl Guile prefix and libdir.
GUILE_PREFIX=`$PKG_CONFIG --print-errors --variable=prefix guile-$GUILE_EFFECTIVE_VERSION`
GUILE_LIBDIR=`$PKG_CONFIG --print-errors --variable=libdir guile-$GUILE_EFFECTIVE_VERSION`
AC_SUBST(GUILE_PREFIX)
AC_SUBST(GUILE_LIBDIR)

guilemoduledir="${datarootdir}/guile/site/${GUILE_EFFECTIVE_VERSION}"
AC_SUBST([guilemoduledir])
AC_SUBST([GUILE_EFFECTIVE_VERSION])

# use Makefile.in
AC_CONFIG_FILES([Makefile])

# output the script
AC_OUTPUT
 

'Makefile.am' 实际上就是 'Makefile' 的模板,它可以包含一个 'guile.am' 的文件,其内容如下:


# guile.am file is included by Makefile.am
# guile.am file is where we have all the code that can be shared
# between any other Guile project.

moddir=$(datadir)/guile/site/$(GUILE_EFFECTIVE_VERSION)
godir=$(libdir)/guile/$(GUILE_EFFECTIVE_VERSION)/site-ccache

GOBJECTS = $(SOURCES:%.scm=%.go)

nobase_dist_mod_DATA = $(SOURCES) $(NOCOMP_SOURCES)
nobase_go_DATA = $(GOBJECTS)

# Make sure source files are installed first, so that the mtime of
# installed compiled files is greater than that of installed source
# files.  See
# <http://lists.gnu.org/archive/html/guile-devel/2010-07/msg00125.html>
# for details.
guile_install_go_files = install-nobase_goDATA
$(guile_install_go_files): install-nobase_dist_modDATA

CLEANFILES = $(GOBJECTS)
GUILE_WARNINGS = -Wunbound-variable -Warity-mismatch -Wformat
SUFFIXES = .scm .go
.scm.go:
	$(AM_V_GEN)$(top_builddir)/pre-inst-env $(GUILD) compile $(GUILE_WARNINGS) -o "$@" "$<"
 

有了以上这几个文件模板和目录结构,创建一个 GNU 软件项目就变得比较简单而标准。

如果你希望自己能够为自由软件作出贡献,并在将来开发一个 GNU 软件项目,那么 立伯乐 或许可以帮你。

让自由软件带你进入的美好自由世界!