massively improved build system

master
Marc Wäckerlin 9 years ago
parent 0d50554c47
commit 8afec7dd28
  1. 17
      README
  2. 41
      ax_check_qt.m4
  3. 67
      ax_init_standard_project.m4
  4. 162
      bootstrap.sh
  5. 13
      src/version.cxx
  6. 14
      src/version.hxx
  7. 2
      src/webrunner.cxx

@ -1,3 +1,18 @@
Test Your Web Application: GUI Web Testing Environment + Script Runner
Webtester consists of two binaries: webtester to interactively create your web application tests and webrunner to run your test scripts.
Webtester consists of two binaries: webtester to interactively create your web application tests and webrunner to run your test scripts.
There is a test GUI including browser to record user input while he surfs on the web and a test runner to run (recorded) test scripts. The tests can be integrated e.g. in a jenkins build job. It has been tested on Wordpress, Dokuwiki and Joomla pages. Joomla is difficult due to Javascript-Moo-Tools pollution. There's some specific support, that may help a bit, but to test Joomla sites, you need a lot of experience. Concluson: Avoid Joomla.
Sample Script to search my old homepage on Google, klick on the link, there click on tab «Computer» and check the title for the text «Marcs Computerblog»:
load https://google.com
expect load
setvalue input[name="q"] -> 'Marc Wäckerlin';
click input[name="btnG"]
expect load
click a[href^="/url?q=https://marc.waeckerlin.org/&"]
expect load https://marc.waeckerlin.org/doku.php
click a[href="/computer/index"]
expect load https://marc.waeckerlin.org/computer/index
exists h1.sectionedit1 -> Marcs Computerblog

@ -1,6 +1,10 @@
# SYNOPSIS
#
# AX_CXX_CHECK_QT([qt_prefix], [list-of-qt-modules], [optional-modules])
# Check if a module exists:
# AX_CXX_CHECK_QT([qt_prefix], [list-of-qt-modules], [optional-modules])
#
# Abort if a module does not exist:
# AX_CXX_REQUIRE_QT([qt_prefix], [list-of-qt-modules], [optional-modules])
#
# DESCRIPTIONS
#
@ -32,6 +36,7 @@
# exist only in Qt5, but not in Qt4, such as QtWidgets or
# QtWebKitWidgets
AC_DEFUN([AX_CXX_QT_TOOL], [
if test -z "$HAVE_$1"; then
HAVE_$1=1
@ -146,6 +151,40 @@ qrc_%.cxx: %.qrc
AC_SUBST(AX_ADDITIONAL_QT_RULES_HACK)
])
# SYNOPSIS
#
# AX_CXX_CHECK_QT([qt_prefix], [list-of-qt-modules], [optional-modules])
#
# DESCRIPTIONS
#
# qt_prefix
#
# Each call to AX_CXX_CHECK_QT should have a different prefix
# value (with a few exceptions discussed later on). This value,
# usually provided in uppercase, is used as prefix to the
# variables holding the compiler flags and libraries reported by
# pkg-config.
#
# For instance, if your prefix was to be FOO you'll be provided
# two variables FOO_CFLAGS and FOO_LIBS.
#
# This will also be used as message during the configure checks:
# checking for FOO....
#
# list-of-modules
#
# A single call to the macro can check for the presence of one or
# more qt modules; you'll see later how to make good use of this
# feature. Each entry in the list can have a version comparison
# specifier, with the same syntax as the Requires keyword in the
# data files themselves.
#
# optional-modules
#
# Optional list of more, optional modules, e.g. modules that
# exist only in Qt5, but not in Qt4, such as QtWidgets or
# QtWebKitWidgets
AC_DEFUN([AX_REQUIRE_QT], [
AX_CHECK_QT([$1], [$2], [$3])
if ! test "$HAVE_$1" -eq 1; then

@ -3,6 +3,8 @@
## 1 2 3 4 5 6 7 8
## 45678901234567890123456789012345678901234567890123456789012345678901234567890
# define least version number from subversion's revision number:
# it is taken modulo 256 due to a bug on Apple's MacOSX
m4_define(x_least, m4_esyscmd_s(
LEAST="ERROR-UNDEFINED-REVISION-to-be-built-in-subdirectory-of-svn-checkout"
for path in . .. ../..; do
@ -15,6 +17,8 @@ m4_define(x_least, m4_esyscmd_s(
done
echo $ECHO_N $LEAST
))
## bugreport mail address is taken from <user@host> in first line of AUTHORS
m4_define(x_bugreport, m4_esyscmd_s(
head -1 AUTHORS | \
sed -n 's,.*<\([-_.a-z0-9A-Z]*@[-_.a-z0-9A-Z]*\)>.*,\1,gp'
@ -38,6 +42,11 @@ dnl refers to ${prefix}. Thus we have to use `eval' twice.
test "$exec_prefix_NONE" && exec_prefix=NONE
])
# add target dependencies to an existing makefile.in
# - parameters:
# $1 = existing target
# $2 = new dependency for that target
# $3 = filename of makefile.in
AC_DEFUN([AX_ADD_MAKEFILE_TARGET_DEP], [
sh_add_makefile_target_dep() {
sed -i ':a;/^'${1}':.*\\$/{N;s/\\\n//;ta};s/^'${1}':.*$/& '${2}'/' "${srcdir}/${3}"
@ -51,13 +60,34 @@ AC_DEFUN([AX_ADD_MAKEFILE_TARGET_DEP], [
fi
])
# Same as AC_SUBST, but adds -Dname="value" option to CPPFLAGS
# - parameters:
# $1 = variable name
AC_DEFUN([AX_SUBST], [
AC_SUBST([$1])
tmp_var="${$1//$'\n'/\n}"
AM_CPPFLAGS+=' -D$1='"'${tmp_var//#/\\#}'"
tmp_var=$(echo "${$1}" | sed ':a;N;$!ba;s/\n/\\n/g')
tmp_var=${tmp_var//\"/\\\"}
tmp_var=${tmp_var//\'/\'\"\'\"\'}
tmp_var=${tmp_var//#/\\#}
AM_CPPFLAGS+=" '-D$1=\"${tmp_var}\"'"
AC_SUBST(AM_CPPFLAGS)
])
# must be called on the right position in configure.ac
#
# configure.ac must start with:
#
# m4_define(x_package_name, YOUR_PACKAGE_NAME) # project's name
# m4_define(x_major, MAJOR_NUMBER) # project's major version
# m4_define(x_minor, MINOR_NUMBER) # project's minor version
# m4_include(ax_init_standard_project.m4)
# AC_INIT(x_package_name, x_major.x_minor.x_least, x_bugreport, x_package_name)
# AM_INIT_AUTOMAKE([1.9 tar-pax])
# AX_INIT_STANDARD_PROJECT
#
# you change nothing but: YOUR_PACKAGE_NAME, MAJOR_NUMBER, MINOR_NUMBER
#
# configures the basic environment
AC_DEFUN([AX_INIT_STANDARD_PROJECT], [
AM_CPPFLAGS+=" '-DMAKE_STRING(X)=\#X' '-DNAMESPACE=${PACKAGE_NAME}'"
AX_SUBST(NUMBERS)
@ -65,31 +95,25 @@ AC_DEFUN([AX_INIT_STANDARD_PROJECT], [
README=$(tail -n +3 README)
AX_SUBST(README)
_AM_SUBST_NOTMAKE([README])
README_STR=$(sed 's,",\\",g; :a;N;$!ba;s/\n/\\n/g' README)
AM_CPPFLAGS+=" '-DREADME_STR=\"${README_STR}\"'"
DESCRIPTION=$(head -1 README)
AX_SUBST(DESCRIPTION)
_AM_SUBST_NOTMAKE([DESCRIPTION])
AUTHOR=$(head -1 AUTHORS)
AX_SUBST(AUTHOR)
_AM_SUBST_NOTMAKE([AUTHOR])
AM_CPPFLAGS+=" '-DAUTHOR_STR=\"${AUTHOR}\"'"
DISTRO=$(lsb_release -sc)
AX_SUBST(DISTRO)
BUILD_NUMBER=${BUILD_NUMBER:-1}
AX_SUBST(BUILD_NUMBER)
BUILD_DATE=$(date -R)
AX_SUBST(BUILD_DATE)
AM_CPPFLAGS+=" '-DBUILD_DATE_STR=\"${BUILD_DATE}\"'"
if test -f "${PROJECT_NAME}-logo.png"; then
PROJECT_LOGO="${PROJECT_NAME}-logo.png"
fi
AX_SUBST(PROJECT_LOGO)
AM_CPPFLAGS+=" '-DPROJECT_LOGO_STR=\"${PROJECT_LOGO}\"'"
if test -f "${PROJECT_NAME}-icon.png"; then
PROJECT_ICON="${PROJECT_NAME}-icon.png"
fi
AM_CPPFLAGS+=" '-DPROJECT_ICON_STR=\"${PROJECT_ICON}\"'"
AX_SUBST(PROJECT_ICON)
AC_CONFIG_FILES([makefile])
AX_ADD_MAKEFILE_TARGET_DEP([clean-am], [clean-standard-project-targets], [makefile.in])
@ -111,6 +135,7 @@ maintainer-clean-standard-project-targets:
EOF
])
# use this in configure.ac to support C++
AC_DEFUN([AX_USE_CXX], [
m4_include(ax_cxx_compile_stdcxx_11.m4)
AC_LANG(C++)
@ -165,6 +190,7 @@ maintainer-clean-cxx-targets:
EOF
])
# use this in configure.ac to support CppUnit for C++ unit tests
AC_DEFUN([AX_USE_CPPUNIT], [
AM_PATH_CPPUNIT([1.0.0], [have_cppunit="yes"], [have_cppunit="no"])
# infos and warnings
@ -182,6 +208,7 @@ maintainer-clean-test-targets:
EOF
])
# use this in configure.ac to support C++ examples
AC_DEFUN([AX_BUILD_EXAMPLES], [
AC_CONFIG_FILES([examples/makefile])
AX_ADD_MAKEFILE_TARGET_DEP([maintainer-clean-am], [maintainer-clean-example-targets], [examples/makefile.in])
@ -193,6 +220,7 @@ maintainer-clean-example-targets:
EOF
])
# use this in configure.ac to support C++ libraries
AC_DEFUN([AX_USE_LIBTOOL], [
# libtool versioning
LIB_MAJOR=m4_eval(x_major+x_minor)
@ -220,6 +248,7 @@ uninstall-data-libtool-pkg:
EOF
])
# use this in configure.ac to support debian packages
AC_DEFUN([AX_USE_DEBIAN_PACKAGING], [
README_DEB=$(tail -n +3 README | sed -e 's/^$/./g' -e 's/^/ /g')
AC_SUBST(README_DEB)
@ -240,6 +269,7 @@ distclean-debian-targets:
EOF
])
# use this in configure.ac to support RPM packages
AC_DEFUN([AX_USE_RPM_PACKAGING], [
# m4_include(ax_rpm_rules.m4)
AC_CONFIG_FILES([${PACKAGE_NAME}.spec])
@ -253,6 +283,7 @@ rpm: dist
EOF
])
# use this in configure.ac to support Doxygen documentation generation
AC_DEFUN([AX_USE_DOXYGEN], [
AC_CHECK_PROG(have_doxygen, doxygen, yes, no)
AC_CHECK_PROG(have_dot, dot, yes, no)
@ -303,6 +334,18 @@ uninstall-documentation:
EOF
])
# require a specific package, with fallback: test for a header
# - parameter:
# $1 = unique id (no special characters)
# $2 = module name
# $3 = a header file to find (optional)
# $4 = alternative module names (space separated, optional)
#
# uses PKG_CHECK_MODULES to test for a module
# then, if given, looks for the header file
# if header file is not found, searches in alternative modules
# sets all flags, so that the module can be used everywhere
# fails if not found
AC_DEFUN([AX_PKG_REQUIRE], [
PKG_PROG_PKG_CONFIG
PKG_CHECK_MODULES([$1], [$2], [
@ -380,6 +423,14 @@ AC_DEFUN([AX_PKG_REQUIRE], [
fi
])
# check if a specific package exists
# - parameter:
# $1 = unique id (no special characters)
# $2 = module name (optional, if different from id)
#
# uses PKG_CHECK_MODULES to test for a module
# sets automake conditional HAVE_$1 to 0 (not found) or 1 (found)
# sets all flags, so that the module can be used everywhere
AC_DEFUN([AX_PKG_CHECK], [
PKG_PROG_PKG_CONFIG
PKG_CHECK_MODULES([$1], [m4_default([$2], [$1])], [

@ -14,20 +14,147 @@
## added file header
##
MY_NAME=${0##*/}
PROJECT_PATH=$(pwd)
DEFAULT_PROJECT_NAME=${PROJECT_PATH##*/}
configure=0
while test $# -gt 0; do
case "$1" in
(--configure|-c) configure=1;;
(--version|-v) echo "$Id$"; exit;;
(--help|-h) less <<EOF
SYNOPSIS
${MY_NAME} [--help|-h] [--configure|-c]
OPTIONS
--configure, -c call ./configure after initialization
--help, -h show this help
--version, -v show version and date of this file
DESCRIPTION
Initializes your build environment, as far as neccessary. Reads your used features from configure.ac, if that file exists, or creates a configure.ac. Automatically copies or creates all required template files.
From your new and empty project's subversion path, call $0 to initialize your build environment.
Before you call ${MY_NAME} the very first time, edit ${0#/*}/AUTHORS and replace it with your name (or the authors of your project, one name each line, main developper and copyright holder on the first line).
The first call to ${MY_NAME} should be something like ../bootstrap-build-environment/${MY_NAME} and not ./${MY_NAME}. Actually, you called $0.
In the way you called ${MY_NAME}, it has detected ${DEFAULT_PROJECT_NAME} as the project name for your project in ${PROJECT_PATH}. In the first run, you should call ${MY_NAME} from a checked out the bootstrap-build-environment from https://dev.marc.waeckerlin.org/, and the path from where you call ${MY_NAME} (which is actually ${PROJECT_PATH}) should be the path to your newly created project. Please note that your project must be a checked out subversion repository, since this build environment relies on subversion.
Example for an initial run, where your new projet is stored in subversion on svn:/path/to/your/new-project:
cd ~/svn
svn co https://dev.marc.waeckerlin.org/svn/bootstrap-build-environment/trunk bootstrap-build-environment
svn co svn:/path/to/your/new-project/trunk new-project
cd new-project
../bootstrap-build-environment/bootstrap.sh
RUNNING
If you run ${MY_NAME}, it first generates the necessary files (see below), then first runs make distclean if a makefile exists. After this it calles aclocal, libtoolize, automake, autoconf and optionally ./configure.
GENERATED FILES
This script copies the following files into your project environment:
* ${MY_NAME}
* ax_init_standard_project.m4 - auxiliary macro definition file
* ax_cxx_compile_stdcxx_11.m4 - auxiliary macro definition file
* ax_check_qt.m4 - auxiliary macro definition file
* AUTHORS - replace your name in AUTHORS before first run
* configure.ac - global configuration file template
* makefile.am - global makefile template
* src/makefile.am - if you enabled AX_USE_CXX
* src/version.hxx - if you enabled AX_USE_CXX
* src/version.cxx - if you enabled AX_USE_CXX
* doc/makefile.am - if you enabled AX_USE_DOXYGEN
* doc/doxyfile.in - if you enabled AX_USE_DOXYGEN
* test/makefile.am - if you enabled AX_USE_CPPUNIT
* examples/makefile.am - if you enabled AX_BUILD_EXAMPLES
* debian/changelog.in - if you enabled AX_USE_DEBIAN_PACKAGING
* debian/control.in - if you enabled AX_USE_DEBIAN_PACKAGING
* debian/docs - if you enabled AX_USE_DEBIAN_PACKAGING
* debian/${DEFAULT_PROJECT_NAME}.install - if you enabled AX_USE_DEBIAN_PACKAGING
* debian/${DEFAULT_PROJECT_NAME}.dirs - if you enabled AX_USE_DEBIAN_PACKAGING
* debian/${DEFAULT_PROJECT_NAME}-dev.install - if you enabled AX_USE_DEBIAN_PACKAGING and AX_USE_LIBTOOL
* debian/${DEFAULT_PROJECT_NAME}-dev.dirs - if you enabled AX_USE_DEBIAN_PACKAGING and AX_USE_LIBTOOL
* debian/rules - if you enabled AX_USE_DEBIAN_PACKAGING
* debian/compat - if you enabled AX_USE_DEBIAN_PACKAGING
* src/${DEFAULT_PROJECT_NAME}.pc.in - if you enabled AX_USE_LIBTOOL
To rebuild any of these files, just remove it using "svn rm <filename>" and run ${MY_NAME} again.
FILES TO EDIT
After creation of the files, you can edit them according to your needs. Please don't forget to redo your edits after rebuilding a file. Most files don't even need to be edited, they work out of the box.
The following files normally require editing:
* AUTHORS
* README
* configure.ac
* src/makefile.am
* test/makefile.am
* examples/makefile.am
FILE DEPENDENCIES
You should rebuild (remove and run (see above) the files, whenever you change the configuration a dependent, i.e.:
* test/makefile.am depends on AX_USE_LIBTOOL
* doc/doxyfile.in depends on AX_BUILD_EXAMPLES
* debian/control.in depends on AX_USE_DOXYGEN, AX_USE_CPPUNIT, AX_CXX_QT, AX_CXX_CHECK_QT, AX_USE_LIBTOOL
* debian/${DEFAULT_PROJECT_NAME}.install depends on AX_USE_LIBTOOL
* debian/${DEFAULT_PROJECT_NAME}.dirs depends on AX_USE_LIBTOOL
* debian/${DEFAULT_PROJECT_NAME}-dev.install depends on AX_USE_LIBTOOL
* debian/${DEFAULT_PROJECT_NAME}-dev.dirs depends on AX_USE_LIBTOOL
FILES
* AUTHORS: First line is the main author and used in Debian and RPM packaging, so there must be a GPG key that matches to this line.
* README: First line is a short description of your project, then an empty line must follow. All remaining lines are a long description of your project. this information is copied, e.g. in Debian or RPM packages. In C++ <ou can access the readme by calling ${DEFAULT_PROJECT_NAME}::description().
* configure.ac: This file becomes very short and simple. You provide the project name, the major and minor version. The least version number is automatically taken from subversion's revision, so every checkin automatically increments the least version number. The following macros are supported:
** Enable C++: AX_USE_CXX
** Enable LibTool library creation: AX_USE_LIBTOOL
** Enable Doxygen documentation generation: AX_USE_DOXYGEN
** Enable debian packaging by calling "make deb": AX_USE_DEBIAN_PACKAGING
** Not yet implemented: AX_USE_RPM_PACKAGING
** Enable C++ testing using CppUnit: AX_USE_CPPUNIT
** Enable C++ examples, i.e. for libraries: AX_BUILD_EXAMPLES
** Check for C++11 support: AX_CXX_COMPILE_STDCXX_11 (see ax_cxx_compile_stdcxx_11.m4)
** Require a QT module: AX_REQUIRE_QT (see ax_check_qt.m4)
** Optionally use a QT module: AX_CHECK_QT (see ax_check_qt.m4)
** Require a module: AX_PKG_REQUIRE (see ax_init_standard_project.m4)
** Check for an optional module: AX_PKG_CHECK (see ax_init_standard_project.m4)
* ChangeLog: Your changelog is automatically maintained from subversion history, using svn2cl. You don't need to care about.
EXAMPLES: src/makefile.am in a QT project
In this example, you wrote the following files:
* ${DEFAULT_PROJECT_NAME}.hxx - Qt Header file, passed to moc
* ${DEFAULT_PROJECT_NAME}.cxx - C++ file containing main()
* ${DEFAULT_PROJECT_NAME}.ui - UI file
All rules are implicitely added, all you need to do is to add the following definitions, most lines are generic:
bin_PROGRAMS = ${DEFAULT_PROJECT_NAME}
${DEFAULT_PROJECT_NAME}_MOCFILES = moc_${DEFAULT_PROJECT_NAME}.cxx
${DEFAULT_PROJECT_NAME}_UIFILES = ui_${DEFAULT_PROJECT_NAME}.hxx
${DEFAULT_PROJECT_NAME}_SOURCES = version.cxx version.hxx ${DEFAULT_PROJECT_NAME}.cxx ${DEFAULT_PROJECT_NAME}_MOCFILES ${DEFAULT_PROJECT_NAME}_UIFILES
BUILT_SOURCES = \${${DEFAULT_PROJECT_NAME}_MOCFILES} \${${DEFAULT_PROJECT_NAME}_UIFILES}
EXTRA_DIST = \${${DEFAULT_PROJECT_NAME}_MOCFILES:moc_%.cxx=%.hxx} \${${DEFAULT_PROJECT_NAME}_UIFILES:ui_%.hxx=%.ui}
MAINTAINERCLEANFILES = makefile.in
EOF
exit;;
(*) break;;
esac
shift;
done
MY_NAME=${0##*/}
PROJECT_PATH=$(pwd)
DEFAULT_PROJECT_NAME=${PROJECT_PATH##*/}
HEADER='## @id $Id$
#
# This file has been added by '${MY_NAME}' on '$(date -R)'
@ -168,7 +295,7 @@ echo "${HEADER}" | to --condition AX_USE_CXX src/makefile.am
to --condition AX_USE_CXX src/version.hxx <<EOF
/*! @file
@id $Id$
@id \$Id$
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
@ -176,15 +303,27 @@ to --condition AX_USE_CXX src/version.hxx <<EOF
#include <string>
namespace NAMESPACE {
/// get package string which consists of package name and package version
std::string package_string();
/// get package name
std::string package_name();
/// get package version
std::string version();
/// get code build date
std::string build_date();
/// get author, i.e. copyright holder
std::string author();
/// get short package description (1st line of README)
std::string description();
/// get long package description (starting at 3rd line in README)
std::string readme();
/// get package logo file name
std::string logo();
/// get package icon file name
std::string icon();
/// used for <code>what filename</code>
extern const std::string WHAT;
/// used for <code>ident filename</code>
extern const std::string IDENT;
}
EOF
@ -209,19 +348,22 @@ namespace NAMESPACE {
return PACKAGE_VERSION;
}
std::string build_date() {
return BUILD_DATE_STR;
return BUILD_DATE;
}
std::string author() {
return AUTHOR_STR;
return AUTHOR;
}
std::string description() {
return README_STR;
return DESCRIPTION;
}
std::string readme() {
return README;
}
std::string logo() {
return PROJECT_LOGO_STR;
return PROJECT_LOGO;
}
std::string icon() {
return PROJECT_ICON_STR;
return PROJECT_ICON;
}
const std::string WHAT("#(@) " PACKAGE_STRING);
const std::string IDENT("\$Id: " PACKAGE_STRING);

@ -18,19 +18,22 @@ namespace NAMESPACE {
return PACKAGE_VERSION;
}
std::string build_date() {
return BUILD_DATE_STR;
return BUILD_DATE;
}
std::string author() {
return AUTHOR_STR;
return AUTHOR;
}
std::string description() {
return README_STR;
return DESCRIPTION;
}
std::string readme() {
return README;
}
std::string logo() {
return PROJECT_LOGO_STR;
return PROJECT_LOGO;
}
std::string icon() {
return PROJECT_ICON_STR;
return PROJECT_ICON;
}
const std::string WHAT("#(@) " PACKAGE_STRING);
const std::string IDENT("$Id: " PACKAGE_STRING);

@ -1,6 +1,6 @@
/*! @file
@id $
@id $Id$
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
@ -8,14 +8,26 @@
#include <string>
namespace NAMESPACE {
/// get package string which consists of package name and package version
std::string package_string();
/// get package name
std::string package_name();
/// get package version
std::string version();
/// get code build date
std::string build_date();
/// get author, i.e. copyright holder
std::string author();
/// get short package description (1st line of README)
std::string description();
/// get long package description (starting at 3rd line in README)
std::string readme();
/// get package logo file name
std::string logo();
/// get package icon file name
std::string icon();
/// used for <code>what filename</code>
extern const std::string WHAT;
/// used for <code>ident filename</code>
extern const std::string IDENT;
}

@ -45,6 +45,8 @@ QString help(const Script& s) {
<<std::endl
<<format(description()).toStdString()<<std::endl
<<std::endl
<<format(readme()).toStdString()<<std::endl
<<std::endl
<<"SCRIPT SYNTAX"<<std::endl
<<std::endl
<<format(s.syntax()).toStdString()<<std::endl

Loading…
Cancel
Save