mirror of https://gitee.com/openkylin/swig.git
Import Upstream version 4.0.2
This commit is contained in:
commit
5025ac6627
|
@ -0,0 +1,536 @@
|
|||
language: cpp
|
||||
matrix:
|
||||
include:
|
||||
- compiler: clang
|
||||
os: linux
|
||||
env: SWIGLANG=
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG= GCC=4.4
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG= GCC=4.6
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG= GCC=4.7
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG= GCC=4.8
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG= GCC=4.9
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG= GCC=6
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG= GCC=7
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG= GCC=8
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG= GCC=9
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=csharp
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=d VER=2.066.0
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=d VER=2.086.1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=go VER=1.3
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=go VER=1.8
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=go VER=1.12
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=guile
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=java
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=javascript ENGINE=node VER=0.10
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=javascript ENGINE=node VER=4 CPP11=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=javascript ENGINE=node VER=6 CPP11=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=javascript ENGINE=node VER=8 CPP11=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=javascript ENGINE=node VER=10 CPP11=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=javascript ENGINE=jsc
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=javascript ENGINE=v8
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=lua
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=lua VER=5.3
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=mzscheme
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=ocaml
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=octave SWIGJOBS=-j2
|
||||
sudo: required
|
||||
dist: xenial # Octave v4.0.0
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=octave SWIGJOBS=-j2 CPP11=1
|
||||
sudo: required
|
||||
dist: bionic # Octave v4.2.2
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=perl5
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=php VER=7.0
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=php VER=7.1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=php VER=7.2
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=php VER=7.3
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=python # 2.7
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=python PY3=3 VER=3.2
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=python PY3=3 VER=3.3
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=python PY3=3 VER=3.4
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=python PY3=3 VER=3.5
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=python PY3=3 VER=3.6
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=python PY3=3 VER=3.7
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=python PY3=3 VER=3.8
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=python SWIG_FEATURES=-builtin
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=python SWIG_FEATURES="-builtin -O"
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=python SWIG_FEATURES=-builtin GCC=6 CPP11=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=python SWIG_FEATURES=-builtin GCC=6 CPP11=1 PY3=3 VER=3.8
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=python SWIG_FEATURES=-builtin PY3=3 VER=3.4
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=python SWIG_FEATURES=-builtin PY3=3 VER=3.5
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=python SWIG_FEATURES=-builtin PY3=3 VER=3.7
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=python SWIG_FEATURES=-builtin PY3=3 VER=3.8
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=python SWIG_FEATURES="-builtin -O" PY3=3 VER=3.8
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=python SWIG_FEATURES=-builtin PY3=3 VER=3.8 SWIGOPTPY3=
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=python SWIG_FEATURES=-O
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=python SWIG_FEATURES=-O PY3=3 VER=3.8
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=r
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=ruby VER=1.9
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=ruby VER=2.0
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=ruby VER=2.1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=ruby VER=2.2
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=ruby VER=2.3
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=ruby VER=2.4
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=ruby VER=2.5
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=ruby VER=2.6
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=ruby VER=2.7
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=scilab
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=tcl
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=csharp CPP11=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=go VER=1.6 CPP11=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=java CPP11=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=python CPP11=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=r CPP11=1 # Note: making 'R CMD SHLIB' use a different compiler is non-trivial
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=ruby CPP11=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=tcl CPP11=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=csharp GCC=6 CPP14=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=go VER=1.6 GCC=6 CPP14=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=java GCC=6 CPP14=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=python GCC=6 CPP14=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=ruby GCC=6 CPP14=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=tcl GCC=6 CPP14=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=java GCC=7 CPP14=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=python GCC=7 CPP14=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=csharp GCC=8 CPP17=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=java GCC=8 CPP17=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=python GCC=8 CPP17=1 PY3=3 VER=3.8
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=csharp GCC=9 CPP17=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=java GCC=9 CPP17=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
env: SWIGLANG=python GCC=9 CPP17=1 PY3=3 VER=3.8
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- os: linux
|
||||
arch: s390x
|
||||
env: SWIGLANG=ruby CPP11=1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: osx
|
||||
env: SWIGLANG=
|
||||
- compiler: clang
|
||||
os: osx
|
||||
env: SWIGLANG=
|
||||
- compiler: clang
|
||||
os: osx
|
||||
env: SWIGLANG=csharp
|
||||
- compiler: clang
|
||||
os: osx
|
||||
env: SWIGLANG=go
|
||||
- compiler: clang
|
||||
os: osx
|
||||
env: SWIGLANG=guile CSTD=c11
|
||||
- compiler: clang
|
||||
os: osx
|
||||
env: SWIGLANG=java
|
||||
- compiler: clang
|
||||
os: osx
|
||||
env: SWIGLANG=lua
|
||||
- compiler: clang
|
||||
os: osx
|
||||
env: SWIGLANG=octave SWIGJOBS=-j2 CPP11=1
|
||||
- compiler: clang
|
||||
os: osx
|
||||
env: SWIGLANG=perl5
|
||||
- compiler: clang
|
||||
os: osx
|
||||
env: SWIGLANG=python
|
||||
- compiler: clang
|
||||
os: osx
|
||||
env: SWIGLANG=python PY3=3
|
||||
- compiler: clang
|
||||
os: osx
|
||||
env: SWIGLANG=ruby
|
||||
- compiler: clang
|
||||
os: osx
|
||||
env: SWIGLANG=tcl
|
||||
- compiler: clang
|
||||
os: osx
|
||||
env: SWIGLANG=java CPP17=1
|
||||
osx_image: xcode10.2
|
||||
- compiler: clang
|
||||
os: osx
|
||||
env: SWIGLANG=python PY3=3 CPP17=1
|
||||
osx_image: xcode10.2
|
||||
|
||||
allow_failures:
|
||||
# Newer version of D not yet working/supported
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=d VER=2.086.1
|
||||
sudo: required
|
||||
dist: xenial
|
||||
# seg fault in director_basic testcase
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=php VER=7.2
|
||||
sudo: required
|
||||
dist: xenial
|
||||
# Experimental languages
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=mzscheme
|
||||
sudo: required
|
||||
dist: xenial
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: SWIGLANG=ocaml
|
||||
sudo: required
|
||||
dist: xenial
|
||||
|
||||
before_install:
|
||||
- date -u
|
||||
- uname -a
|
||||
- if test "$TRAVIS_OS_NAME" = "linux"; then lscpu; grep "model name" /proc/cpuinfo || echo 'Unknown CPU model'; grep "MemTotal" /proc/meminfo || echo 'Unknown system memory amount'; fi
|
||||
- if test "$TRAVIS_OS_NAME" = "osx"; then sysctl -a | grep brand_string; fi
|
||||
# Travis overrides CC environment with compiler predefined values
|
||||
- if test -n "$GCC"; then export CC="gcc-$GCC" && export CXX="g++-$GCC"; fi
|
||||
install:
|
||||
- if test "$TRAVIS_OS_NAME" = "linux"; then source Tools/travis-linux-install.sh; fi
|
||||
- if test "$TRAVIS_OS_NAME" = "osx"; then source Tools/travis-osx-install.sh; fi
|
||||
- ls -la $(which $CC) $(which $CXX) && $CC --version && $CXX --version
|
||||
script:
|
||||
- echo 'Configuring...' && echo -en 'travis_fold:start:script.1\\r'
|
||||
- if test -n "$CPP11"; then CONFIGOPTS+=(--enable-cpp11-testing --without-maximum-compile-warnings "CXXFLAGS=-std=c++11 -Wall -Wextra" "CFLAGS=-std=c11 -Wall -Wextra") && export CSTD=c11 && export CPPSTD=c++11; fi
|
||||
- if test -n "$CPP14"; then CONFIGOPTS+=(--enable-cpp11-testing --without-maximum-compile-warnings "CXXFLAGS=-std=c++14 -Wall -Wextra" "CFLAGS=-std=c11 -Wall -Wextra") && export CSTD=c11 && export CPPSTD=c++14; fi
|
||||
- if test -n "$CPP17"; then CONFIGOPTS+=(--enable-cpp11-testing --without-maximum-compile-warnings "CXXFLAGS=-std=c++17 -Wall -Wextra" "CFLAGS=-std=c17 -Wall -Wextra") && export CSTD=c17 && export CPPSTD=c++17; fi
|
||||
- if test -n "$SWIGLANG"; then CONFIGOPTS+=(--without-alllang --with-$WITHLANG); fi
|
||||
- echo "${CONFIGOPTS[@]}"
|
||||
- ./autogen.sh && mkdir -p build/build && cd build/build && ../../configure "${CONFIGOPTS[@]}"
|
||||
- echo -en 'travis_fold:end:script.1\\r'
|
||||
- make -s $SWIGJOBS
|
||||
- ./swig -version && ./swig -pcreversion
|
||||
- if test -z "$SWIGLANG"; then make -s $SWIGJOBS check-ccache; fi
|
||||
- if test -z "$SWIGLANG"; then make -s $SWIGJOBS check-errors-test-suite; fi
|
||||
- echo 'Installing...' && echo -en 'travis_fold:start:script.2\\r'
|
||||
- if test -z "$SWIGLANG"; then sudo make -s install && swig -version && ccache-swig -V; fi
|
||||
- echo -en 'travis_fold:end:script.2\\r'
|
||||
# Stricter compile flags for examples. Various headers and SWIG generated code prevents full use of -pedantic.
|
||||
- if test -n "$SWIGLANG"; then cflags=$($TRAVIS_BUILD_DIR/Tools/testflags.py --language $SWIGLANG --cflags --std=$CSTD --compiler=$CC) && echo $cflags; fi
|
||||
- if test -n "$SWIGLANG"; then cxxflags=$($TRAVIS_BUILD_DIR/Tools/testflags.py --language $SWIGLANG --cxxflags --std=$CPPSTD --compiler=$CC) && echo $cxxflags; fi
|
||||
- if test -n "$SWIGLANG"; then make -s check-$SWIGLANG-version; fi
|
||||
- if test -n "$SWIGLANG"; then make check-$SWIGLANG-enabled; fi
|
||||
- if test -n "$SWIGLANG"; then make $SWIGJOBS check-$SWIGLANG-examples CFLAGS="$cflags" CXXFLAGS="$cxxflags"; fi
|
||||
- if test -n "$SWIGLANG"; then make $SWIGJOBS check-$SWIGLANG-test-suite CFLAGS="$cflags" CXXFLAGS="$cxxflags"; fi
|
||||
- echo 'Cleaning...' && echo -en 'travis_fold:start:script.3\\r'
|
||||
- make check-maintainer-clean && ../../configure $CONFIGOPTS
|
||||
- echo -en 'travis_fold:end:script.3\\r'
|
|
@ -0,0 +1,38 @@
|
|||
*** ANNOUNCE: SWIG 4.0.2 (8 Jun 2020) ***
|
||||
|
||||
http://www.swig.org
|
||||
|
||||
We're pleased to announce SWIG-4.0.2, the latest SWIG release.
|
||||
|
||||
What is SWIG?
|
||||
=============
|
||||
|
||||
SWIG is a software development tool that reads C/C++ header files and
|
||||
generates the wrapper code needed to make C and C++ code accessible
|
||||
from other programming languages including Perl, Python, Tcl, Ruby,
|
||||
PHP, C#, Go, Java, Javascript, Lua, Scheme (Guile, MzScheme), D,
|
||||
Ocaml, Octave, R, Scilab. SWIG can also export its parse tree in
|
||||
the form of XML. Major applications of SWIG include generation of
|
||||
scripting language extension modules, rapid prototyping, testing,
|
||||
and user interface development for large C/C++ systems.
|
||||
|
||||
Release Notes
|
||||
=============
|
||||
Detailed release notes are available with the release and are also
|
||||
published on the SWIG web site at http://swig.org/release.html.
|
||||
|
||||
Availability
|
||||
============
|
||||
The release is available for download on Sourceforge at
|
||||
|
||||
http://prdownloads.sourceforge.net/swig/swig-4.0.2.tar.gz
|
||||
|
||||
A Windows version is also available at
|
||||
|
||||
http://prdownloads.sourceforge.net/swig/swigwin-4.0.2.zip
|
||||
|
||||
Please report problems with this release to the swig-devel mailing list,
|
||||
details at http://www.swig.org/mail.html.
|
||||
|
||||
--- The SWIG Developers
|
||||
|
|
@ -0,0 +1,339 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
|
@ -0,0 +1,84 @@
|
|||
datarootdir = @datarootdir@
|
||||
srcdir=@srcdir@
|
||||
VPATH=@srcdir@
|
||||
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
bindir=@bindir@
|
||||
mandir=@mandir@
|
||||
INSTALLCMD=@INSTALL@
|
||||
PACKAGE_NAME=@PACKAGE_NAME@
|
||||
PROGRAM_NAME=@PROGRAM_NAME@
|
||||
# Soft link test can be skipped on systems that don't support soft linking
|
||||
NOSOFTLINKSTEST=
|
||||
|
||||
CC=@CC@
|
||||
CFLAGS=@CFLAGS@ -I.
|
||||
SWIG=swig
|
||||
SWIG_LIB=../$(srcdir)/../Lib
|
||||
EXEEXT=@EXEEXT@
|
||||
|
||||
LIBS= @LIBS@
|
||||
OBJS= ccache.o mdfour.o hash.o execute.o util.o args.o stats.o \
|
||||
cleanup.o snprintf.o unify.o
|
||||
HEADERS = ccache.h mdfour.h config.h config_win32.h
|
||||
|
||||
all: $(PACKAGE_NAME)$(EXEEXT)
|
||||
|
||||
# Regenerate Makefile if Makefile.in or config.status have changed.
|
||||
Makefile: $(srcdir)/Makefile.in ./config.status
|
||||
$(SHELL) ./config.status
|
||||
|
||||
# Note that HTML documentation is actually generated and used from the main SWIG documentation Makefile
|
||||
docs: $(srcdir)/$(PACKAGE_NAME).1 $(srcdir)/web/$(PACKAGE_NAME)-man.html
|
||||
|
||||
$(PACKAGE_NAME)$(EXEEXT): $(OBJS) $(HEADERS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||
|
||||
$(srcdir)/$(PACKAGE_NAME).1: $(srcdir)/ccache.yo
|
||||
-yodl2man -o $(srcdir)/$(PACKAGE_NAME).1 $(srcdir)/ccache.yo
|
||||
|
||||
$(srcdir)/web/$(PACKAGE_NAME)-man.html: $(srcdir)/ccache.yo
|
||||
yodl2html -o $(srcdir)/web/$(PACKAGE_NAME)-man.html $(srcdir)/ccache.yo
|
||||
|
||||
install: $(PACKAGE_NAME)$(EXEEXT)
|
||||
@echo "Installing $(PACKAGE_NAME)"
|
||||
@echo "Installing $(DESTDIR)${bindir}/$(PROGRAM_NAME)$(EXEEXT)"
|
||||
${INSTALLCMD} -d $(DESTDIR)${bindir}
|
||||
${INSTALLCMD} -m 755 $(PACKAGE_NAME)$(EXEEXT) $(DESTDIR)${bindir}/$(PROGRAM_NAME)$(EXEEXT)
|
||||
|
||||
install-docs: $(srcdir)/$(PACKAGE_NAME).1
|
||||
@echo "Installing $(DESTDIR)${mandir}/man1/$(PROGRAM_NAME).1"
|
||||
${INSTALLCMD} -d $(DESTDIR)${mandir}/man1
|
||||
${INSTALLCMD} -m 644 $(srcdir)/$(PACKAGE_NAME).1 $(DESTDIR)${mandir}/man1/$(PROGRAM_NAME).1
|
||||
|
||||
uninstall: $(PACKAGE_NAME)$(EXEEXT)
|
||||
rm -f $(DESTDIR)${bindir}/$(PROGRAM_NAME)$(EXEEXT)
|
||||
|
||||
uninstall-docs: $(srcdir)/$(PACKAGE_NAME).1
|
||||
rm -f $(DESTDIR)${mandir}/man1/$(PROGRAM_NAME).1
|
||||
|
||||
clean: clean-docs
|
||||
/bin/rm -f $(OBJS) *~ $(PACKAGE_NAME)$(EXEEXT)
|
||||
|
||||
clean-docs:
|
||||
rm -f $(srcdir)/$(PACKAGE_NAME).1 $(srcdir)/web/$(PACKAGE_NAME)-man.html
|
||||
|
||||
test: test.sh
|
||||
SWIG_LIB='$(SWIG_LIB)' PATH=../..:$$PATH SWIG='$(SWIG)' CC='$(CC)' NOSOFTLINKSTEST='$(NOSOFTLINKSTEST)' CCACHE='../$(PACKAGE_NAME)' CCACHE_PROG=$(PROGRAM_NAME) $(srcdir)/test.sh
|
||||
|
||||
check: test
|
||||
|
||||
distclean: clean
|
||||
/bin/rm -f Makefile config.h config.sub config.log build-stamp config.status ccache_swig_config.h config_win32.h
|
||||
/bin/rm -rf autom4te.cache
|
||||
|
||||
maintainer-clean: distclean
|
||||
/bin/rm -f $(srcdir)/$(PACKAGE_NAME).1 $(srcdir)/web/$(PACKAGE_NAME)-man.html
|
||||
|
||||
|
||||
# FIXME: To fix this, test.sh needs to be able to take ccache from the
|
||||
# installed prefix, not from the source dir.
|
||||
installcheck:
|
||||
@echo "WARNING! This is not really \"installcheck\" yet."
|
||||
$(MAKE) check
|
|
@ -0,0 +1,31 @@
|
|||
This is a re-implementation of "compilercache" in C
|
||||
|
||||
The original compilercache scripts were by Erik Thiele
|
||||
(erikyyy@erikyyy.de) and I would like to thank him for an excellent
|
||||
piece of work. See http://www.erikyyy.de/compilercache/ for the
|
||||
original shell scripts.
|
||||
|
||||
I wrote ccache because I wanted to get a bit more speed out of a
|
||||
compiler cache and I wanted to remove some of the limitations of the
|
||||
shell-script version.
|
||||
|
||||
Please see the manual page and documentation at
|
||||
http://ccache.samba.org/
|
||||
|
||||
INSTALLATION
|
||||
------------
|
||||
|
||||
Please run:
|
||||
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
|
||||
then read the ccache manual page
|
||||
|
||||
-----------
|
||||
|
||||
Andrew Tridgell
|
||||
http://samba.org/~tridge/
|
||||
bugs@ccache.samba.org
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
This directory contains a version of ccache. The initial version was based on ccache-2.4 plus
|
||||
debian patches 01-02, 04-14, see the debian/patches subdirectory. The ccache-win32-2.4 modifications
|
||||
to ccache-2.4 have also been merged in.
|
||||
|
||||
Changes have been made to support cacheing the output from SWIG. The ability to cache c/c++ compiler
|
||||
output has been retained.
|
||||
|
||||
Additional features added are the CCACHE_VERBOSE and CCACHE_SWIG environment variables, see docs.
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
convenient routines for argument list handling
|
||||
|
||||
Copyright (C) Andrew Tridgell 2002
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "ccache.h"
|
||||
|
||||
ARGS *args_init(int init_argc, char **init_args)
|
||||
{
|
||||
ARGS *args;
|
||||
int i;
|
||||
args = (ARGS *)x_malloc(sizeof(ARGS));
|
||||
args->argc = 0;
|
||||
args->argv = (char **)x_malloc(sizeof(char *));
|
||||
args->argv[0] = NULL;
|
||||
for (i=0;i<init_argc;i++) {
|
||||
args_add(args, init_args[i]);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
|
||||
void args_add(ARGS *args, const char *s)
|
||||
{
|
||||
args->argv = (char**)x_realloc(args->argv, (args->argc + 2) * sizeof(char *));
|
||||
args->argv[args->argc] = x_strdup(s);
|
||||
args->argc++;
|
||||
args->argv[args->argc] = NULL;
|
||||
}
|
||||
|
||||
/* pop the last element off the args list */
|
||||
void args_pop(ARGS *args, int n)
|
||||
{
|
||||
while (n--) {
|
||||
args->argc--;
|
||||
free(args->argv[args->argc]);
|
||||
args->argv[args->argc] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* remove the first element of the argument list */
|
||||
void args_remove_first(ARGS *args)
|
||||
{
|
||||
free(args->argv[0]);
|
||||
memmove(&args->argv[0],
|
||||
&args->argv[1],
|
||||
args->argc * sizeof(args->argv[0]));
|
||||
args->argc--;
|
||||
}
|
||||
|
||||
/* add an argument into the front of the argument list */
|
||||
void args_add_prefix(ARGS *args, const char *s)
|
||||
{
|
||||
args->argv = (char**)x_realloc(args->argv, (args->argc + 2) * sizeof(char *));
|
||||
memmove(&args->argv[1], &args->argv[0],
|
||||
(args->argc+1) * sizeof(args->argv[0]));
|
||||
args->argv[0] = x_strdup(s);
|
||||
args->argc++;
|
||||
}
|
||||
|
||||
/* strip any arguments beginning with the specified prefix */
|
||||
void args_strip(ARGS *args, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<args->argc; ) {
|
||||
if (strncmp(args->argv[i], prefix, strlen(prefix)) == 0) {
|
||||
free(args->argv[i]);
|
||||
memmove(&args->argv[i],
|
||||
&args->argv[i+1],
|
||||
args->argc * sizeof(args->argv[i]));
|
||||
args->argc--;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,209 @@
|
|||
#include "ccache_swig_config.h"
|
||||
|
||||
#define CCACHE_VERSION SWIG_VERSION
|
||||
|
||||
#ifndef _WIN32
|
||||
#include "config.h"
|
||||
#else
|
||||
#include <sys/locking.h>
|
||||
#include "config_win32.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mman.h>
|
||||
#else
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0500
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#endif
|
||||
|
||||
#include <sys/file.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <utime.h>
|
||||
#include <stdarg.h>
|
||||
#include <dirent.h>
|
||||
#include <limits.h>
|
||||
#ifdef HAVE_PWD_H
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_ZLIB
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
#define STATUS_NOTFOUND 3
|
||||
#define STATUS_FATAL 4
|
||||
#define STATUS_NOCACHE 5
|
||||
|
||||
#define MYNAME PROGRAM_NAME
|
||||
|
||||
#define LIMIT_MULTIPLE 0.8
|
||||
|
||||
/* default maximum cache size */
|
||||
#ifndef DEFAULT_MAXSIZE
|
||||
#define DEFAULT_MAXSIZE (1000*1000)
|
||||
#endif
|
||||
|
||||
/* file copy mode */
|
||||
#ifdef ENABLE_ZLIB
|
||||
#define COPY_UNCOMPRESSED 0
|
||||
#define COPY_FROM_CACHE 1
|
||||
#define COPY_TO_CACHE 2
|
||||
#endif
|
||||
|
||||
enum stats {
|
||||
STATS_NONE=0,
|
||||
STATS_STDOUT,
|
||||
STATS_STATUS,
|
||||
STATS_ERROR,
|
||||
STATS_TOCACHE,
|
||||
STATS_PREPROCESSOR,
|
||||
STATS_COMPILER,
|
||||
STATS_MISSING,
|
||||
STATS_CACHED,
|
||||
STATS_ARGS,
|
||||
STATS_LINK,
|
||||
STATS_NUMFILES,
|
||||
STATS_TOTALSIZE,
|
||||
STATS_MAXFILES,
|
||||
STATS_MAXSIZE,
|
||||
STATS_NOTC,
|
||||
STATS_DEVICE,
|
||||
STATS_NOINPUT,
|
||||
STATS_ENVIRONMMENT,
|
||||
STATS_MULTIPLE,
|
||||
STATS_CONFTEST,
|
||||
STATS_UNSUPPORTED,
|
||||
STATS_OUTSTDOUT,
|
||||
|
||||
STATS_END
|
||||
};
|
||||
|
||||
typedef unsigned uint32;
|
||||
|
||||
#include "mdfour.h"
|
||||
|
||||
void hash_start(void);
|
||||
void hash_string(const char *s);
|
||||
void hash_int(int x);
|
||||
void hash_file(const char *fname);
|
||||
char *hash_result(void);
|
||||
void hash_buffer(const char *s, int len);
|
||||
|
||||
void cc_log(const char *format, ...);
|
||||
void fatal(const char *msg);
|
||||
|
||||
void copy_fd(int fd_in, int fd_out);
|
||||
int safe_rename(const char* oldpath, const char* newpath);
|
||||
int move_file(const char *src, const char *dest);
|
||||
int test_if_compressed(const char *filename);
|
||||
|
||||
int commit_to_cache(const char *src, const char *dest, int hardlink);
|
||||
int retrieve_from_cache(const char *src, const char *dest, int hardlink);
|
||||
|
||||
int create_dir(const char *dir);
|
||||
int create_cachedirtag(const char *dir);
|
||||
void x_asprintf(char **ptr, const char *format, ...);
|
||||
char *x_strdup(const char *s);
|
||||
void *x_realloc(void *ptr, size_t size);
|
||||
void *x_malloc(size_t size);
|
||||
void traverse(const char *dir, void (*fn)(const char *, struct stat *));
|
||||
char *str_basename(const char *s);
|
||||
char *dirname(char *s);
|
||||
int lock_fd(int fd);
|
||||
size_t file_size(struct stat *st);
|
||||
int safe_open(const char *fname);
|
||||
char *x_realpath(const char *path);
|
||||
char *gnu_getcwd(void);
|
||||
int create_empty_file(const char *fname);
|
||||
const char *get_home_directory(void);
|
||||
int x_utimes(const char *filename);
|
||||
#ifdef _WIN32
|
||||
void perror_win32(LPTSTR pszFunction);
|
||||
#endif
|
||||
|
||||
void stats_update(enum stats stat);
|
||||
void stats_zero(void);
|
||||
void stats_summary(void);
|
||||
void stats_tocache(size_t size, size_t numfiles);
|
||||
void stats_read(const char *stats_file, unsigned counters[STATS_END]);
|
||||
int stats_set_limits(long maxfiles, long maxsize);
|
||||
size_t value_units(const char *s);
|
||||
void display_size(unsigned v);
|
||||
void stats_set_sizes(const char *dir, size_t num_files, size_t total_size);
|
||||
|
||||
int unify_hash(const char *fname);
|
||||
|
||||
#ifndef HAVE_VASPRINTF
|
||||
int vasprintf(char **, const char *, va_list );
|
||||
#endif
|
||||
#ifndef HAVE_ASPRINTF
|
||||
int asprintf(char **ptr, const char *format, ...);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SNPRINTF
|
||||
int snprintf(char *,size_t ,const char *, ...);
|
||||
#endif
|
||||
|
||||
void cleanup_dir(const char *dir, size_t maxfiles, size_t maxsize, size_t minfiles);
|
||||
void cleanup_all(const char *dir);
|
||||
void wipe_all(const char *dir);
|
||||
|
||||
#ifdef _WIN32
|
||||
char *argvtos(char **argv);
|
||||
#endif
|
||||
int execute(char **argv,
|
||||
const char *path_stdout,
|
||||
const char *path_stderr);
|
||||
char *find_executable(const char *name, const char *exclude_name);
|
||||
void display_execute_args(char **argv);
|
||||
|
||||
typedef struct {
|
||||
char **argv;
|
||||
int argc;
|
||||
} ARGS;
|
||||
|
||||
|
||||
ARGS *args_init(int , char **);
|
||||
void args_add(ARGS *args, const char *s);
|
||||
void args_add_prefix(ARGS *args, const char *s);
|
||||
void args_pop(ARGS *args, int n);
|
||||
void args_strip(ARGS *args, const char *prefix);
|
||||
void args_remove_first(ARGS *args);
|
||||
|
||||
extern int ccache_verbose;
|
||||
|
||||
#if HAVE_COMPAR_FN_T
|
||||
#define COMPAR_FN_T __compar_fn_t
|
||||
#else
|
||||
typedef int (*COMPAR_FN_T)(const void *, const void *);
|
||||
#endif
|
||||
|
||||
/* work with silly DOS binary open */
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
/* mkstemp() on some versions of cygwin don't handle binary files, so
|
||||
override */
|
||||
/* Seems okay in Cygwin 1.7.0
|
||||
#ifdef __CYGWIN__
|
||||
#undef HAVE_MKSTEMP
|
||||
#endif
|
||||
*/
|
|
@ -0,0 +1,422 @@
|
|||
whenman(
|
||||
COMMENT(html output not great if included when using html2doc)
|
||||
manpage(ccache-swig)(1)()()()
|
||||
)
|
||||
|
||||
whenhtml(htmlcommand(
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>ccache-swig(1) manpage</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<H1><a name="CCache"></a>Using SWIG with ccache - ccache-swig(1) manpage</H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<!-- INDEX -->
|
||||
|
||||
))
|
||||
|
||||
|
||||
manpagename(ccache-swig)(a fast compiler cache)
|
||||
|
||||
whenhtml(htmlcommand(
|
||||
ccache-swig - a fast compiler cache
|
||||
))
|
||||
|
||||
manpagesynopsis()
|
||||
|
||||
ccache-swig [OPTION]
|
||||
|
||||
ccache-swig <compiler> [COMPILER OPTIONS]
|
||||
|
||||
<compiler> [COMPILER OPTIONS]
|
||||
|
||||
manpagedescription()
|
||||
|
||||
ccache-swig is a compiler cache. It speeds up re-compilation of C/C++/SWIG code
|
||||
by caching previous compiles and detecting when the same compile is
|
||||
being done again. ccache-swig is ccache plus support for SWIG. ccache
|
||||
and ccache-swig are used interchangeably in this document.
|
||||
|
||||
manpagesection(OPTIONS SUMMARY)
|
||||
|
||||
Here is a summary of the options to ccache-swig.
|
||||
|
||||
verb(
|
||||
-s show statistics summary
|
||||
-z zero statistics
|
||||
-c run a cache cleanup
|
||||
-C clear the cache completely
|
||||
-F <n> set maximum files in cache
|
||||
-M <n> set maximum size of cache (use G, M or K)
|
||||
-h this help page
|
||||
-V print version number
|
||||
)
|
||||
|
||||
manpageoptions()
|
||||
|
||||
These options only apply when you invoke ccache as "ccache-swig". When
|
||||
invoked as a compiler none of these options apply. In that case your
|
||||
normal compiler options apply and you should refer to your compilers
|
||||
documentation.
|
||||
|
||||
startdit()
|
||||
dit(bf(-h)) Print a options summary page
|
||||
|
||||
dit(bf(-s)) Print the current statistics summary for the cache. The
|
||||
statistics are stored spread across the subdirectories of the
|
||||
cache. Using "ccache-swig -s" adds up the statistics across all
|
||||
subdirectories and prints the totals.
|
||||
|
||||
dit(bf(-z)) Zero the cache statistics.
|
||||
|
||||
dit(bf(-V)) Print the ccache version number
|
||||
|
||||
dit(bf(-c)) Clean the cache and re-calculate the cache file count and
|
||||
size totals. Normally the -c option should not be necessary as ccache
|
||||
keeps the cache below the specified limits at runtime and keeps
|
||||
statistics up to date on each compile. This option is mostly useful
|
||||
if you manually modify the cache contents or believe that the cache
|
||||
size statistics may be inaccurate.
|
||||
|
||||
dit(bf(-C)) Clear the entire cache, removing all cached files.
|
||||
|
||||
dit(bf(-F <maxfiles>)) This sets the maximum number of files allowed in
|
||||
the cache. The value is stored inside the cache directory and applies
|
||||
to all future compiles. Due to the way the value is stored the actual
|
||||
value used is always rounded down to the nearest multiple of 16.
|
||||
|
||||
dit(bf(-M <maxsize>)) This sets the maximum cache size. You can specify
|
||||
a value in gigabytes, megabytes or kilobytes by appending a G, M or K
|
||||
to the value. The default is gigabytes. The actual value stored is
|
||||
rounded down to the nearest multiple of 16 kilobytes.
|
||||
|
||||
enddit()
|
||||
|
||||
manpagesection(INSTALLATION)
|
||||
|
||||
There are two ways to use ccache. You can either prefix your compile
|
||||
commands with "ccache-swig" or you can create a symbolic link between
|
||||
ccache-swig and the names of your compilers. The first method is most
|
||||
convenient if you just want to try out ccache or wish to use it for
|
||||
some specific projects. The second method is most useful for when you
|
||||
wish to use ccache for all your compiles.
|
||||
|
||||
To install for usage by the first method just copy ccache-swig to somewhere
|
||||
in your path.
|
||||
|
||||
To install for the second method do something like this:
|
||||
verb(
|
||||
cp ccache-swig /usr/local/bin/
|
||||
ln -s /usr/local/bin/ccache-swig /usr/local/bin/gcc
|
||||
ln -s /usr/local/bin/ccache-swig /usr/local/bin/g++
|
||||
ln -s /usr/local/bin/ccache-swig /usr/local/bin/cc
|
||||
ln -s /usr/local/bin/ccache-swig /usr/local/bin/swig
|
||||
)
|
||||
This will work as long as /usr/local/bin comes before the path to gcc
|
||||
(which is usually in /usr/bin). After installing you may wish to run
|
||||
"which gcc" to make sure that the correct link is being used.
|
||||
|
||||
Note! Do not use a hard link, use a symbolic link. A hardlink will
|
||||
cause "interesting" problems.
|
||||
|
||||
manpagesection(EXTRA OPTIONS)
|
||||
|
||||
When run as a compiler front end ccache usually just takes the same
|
||||
command line options as the compiler you are using. The only exception
|
||||
to this is the option '--ccache-skip'. That option can be used to tell
|
||||
ccache that the next option is definitely not a input filename, and
|
||||
should be passed along to the compiler as-is.
|
||||
|
||||
The reason this can be important is that ccache does need to parse the
|
||||
command line and determine what is an input filename and what is a
|
||||
compiler option, as it needs the input filename to determine the name
|
||||
of the resulting object file (among other things). The heuristic
|
||||
ccache uses in this parse is that any string on the command line that
|
||||
exists as a file is treated as an input file name (usually a C
|
||||
file). By using --ccache-skip you can force an option to not be
|
||||
treated as an input file name and instead be passed along to the
|
||||
compiler as a command line option.
|
||||
|
||||
manpagesection(ENVIRONMENT VARIABLES)
|
||||
|
||||
ccache uses a number of environment variables to control operation. In
|
||||
most cases you won't need any of these as the defaults will be fine.
|
||||
|
||||
startdit()
|
||||
|
||||
dit(bf(CCACHE_DIR)) the CCACHE_DIR environment variable specifies
|
||||
where ccache will keep its cached compiler output. The default is
|
||||
"$HOME/.ccache".
|
||||
|
||||
dit(bf(CCACHE_TEMPDIR)) the CCACHE_TEMPDIR environment variable specifies
|
||||
where ccache will put temporary files. The default is the same as
|
||||
CCACHE_DIR. Note that the CCACHE_TEMPDIR path must be on the same
|
||||
filesystem as the CCACHE_DIR path, so that renames of files between
|
||||
the two directories can work.
|
||||
|
||||
dit(bf(CCACHE_LOGFILE)) If you set the CCACHE_LOGFILE environment
|
||||
variable then ccache will write some log information on cache hits
|
||||
and misses in that file. This is useful for tracking down problems.
|
||||
|
||||
dit(bf(CCACHE_VERBOSE)) If you set the CCACHE_VERBOSE environment
|
||||
variable then ccache will display on stdout all the compiler invocations
|
||||
that it makes. This can useful for debugging unexpected problems.
|
||||
|
||||
dit(bf(CCACHE_PATH)) You can optionally set CCACHE_PATH to a colon
|
||||
separated path where ccache will look for the real compilers. If you
|
||||
don't do this then ccache will look for the first executable matching
|
||||
the compiler name in the normal PATH that isn't a symbolic link to
|
||||
ccache itself.
|
||||
|
||||
dit(bf(CCACHE_CC)) You can optionally set CCACHE_CC to force the name
|
||||
of the compiler to use. If you don't do this then ccache works it out
|
||||
from the command line.
|
||||
|
||||
dit(bf(CCACHE_PREFIX)) This option adds a prefix to the command line
|
||||
that ccache runs when invoking the compiler. Also see the section
|
||||
below on using ccache with distcc.
|
||||
|
||||
dit(bf(CCACHE_DISABLE)) If you set the environment variable
|
||||
CCACHE_DISABLE then ccache will just call the real compiler,
|
||||
bypassing the cache completely.
|
||||
|
||||
dit(bf(CCACHE_READONLY)) the CCACHE_READONLY environment variable
|
||||
tells ccache to attempt to use existing cached object files, but not
|
||||
to try to add anything new to the cache. If you are using this because
|
||||
your CCACHE_DIR is read-only, then you may find that you also need to
|
||||
set CCACHE_TEMPDIR as otherwise ccache will fail to create the
|
||||
temporary files.
|
||||
|
||||
dit(bf(CCACHE_CPP2)) If you set the environment variable CCACHE_CPP2
|
||||
then ccache will not use the optimisation of avoiding the 2nd call to
|
||||
the pre-processor by compiling the pre-processed output that was used
|
||||
for finding the hash in the case of a cache miss. This is primarily a
|
||||
debugging option, although it is possible that some unusual compilers
|
||||
will have problems with the intermediate filename extensions used in
|
||||
this optimisation, in which case this option could allow ccache to be
|
||||
used.
|
||||
|
||||
dit(bf(CCACHE_NOCOMPRESS)) If you set the environment variable
|
||||
CCACHE_NOCOMPRESS then there is no compression used on files that go
|
||||
into the cache. However, this setting has no effect on how files are
|
||||
retrieved from the cache, compressed results will still be usable.
|
||||
|
||||
dit(bf(CCACHE_NOSTATS)) If you set the environment variable
|
||||
CCACHE_NOSTATS then ccache will not update the statistics files on
|
||||
each compile.
|
||||
|
||||
dit(bf(CCACHE_NLEVELS)) The environment variable CCACHE_NLEVELS allows
|
||||
you to choose the number of levels of hash in the cache directory. The
|
||||
default is 2. The minimum is 1 and the maximum is 8.
|
||||
|
||||
dit(bf(CCACHE_HARDLINK)) If you set the environment variable
|
||||
CCACHE_HARDLINK then ccache will attempt to use hard links from the
|
||||
cache directory when creating the compiler output rather than using a
|
||||
file copy. Using hard links is faster, but can confuse programs like
|
||||
'make' that rely on modification times. Hard links are never made for
|
||||
compressed cache files.
|
||||
|
||||
dit(bf(CCACHE_RECACHE)) This forces ccache to not use any cached
|
||||
results, even if it finds them. New results are still cached, but
|
||||
existing cache entries are ignored.
|
||||
|
||||
dit(bf(CCACHE_UMASK)) This sets the umask for ccache and all child
|
||||
processes (such as the compiler). This is mostly useful when you wish
|
||||
to share your cache with other users. Note that this also affects the
|
||||
file permissions set on the object files created from your
|
||||
compilations.
|
||||
|
||||
dit(bf(CCACHE_HASHDIR)) This tells ccache to hash the current working
|
||||
directory when calculating the hash that is used to distinguish two
|
||||
compiles. This prevents a problem with the storage of the current
|
||||
working directory in the debug info of a object file, which can lead
|
||||
ccache to give a cached object file that has the working directory in
|
||||
the debug info set incorrectly. This option is off by default as the
|
||||
incorrect setting of this debug info rarely causes problems. If you
|
||||
strike problems with gdb not using the correct directory then enable
|
||||
this option.
|
||||
|
||||
dit(bf(CCACHE_UNIFY)) If you set the environment variable CCACHE_UNIFY
|
||||
then ccache will use the C/C++ unifier when hashing the pre-processor
|
||||
output if -g is not used in the compile. The unifier is slower than a
|
||||
normal hash, so setting this environment variable loses a little bit
|
||||
of speed, but it means that ccache can take advantage of not
|
||||
recompiling when the changes to the source code consist of
|
||||
reformatting only. Note that using CCACHE_UNIFY changes the hash, so
|
||||
cached compiles with CCACHE_UNIFY set cannot be used when
|
||||
CCACHE_UNIFY is not set and vice versa. The reason the unifier is off
|
||||
by default is that it can give incorrect line number information in
|
||||
compiler warning messages.
|
||||
|
||||
dit(bf(CCACHE_EXTENSION)) Normally ccache tries to automatically
|
||||
determine the extension to use for intermediate C pre-processor files
|
||||
based on the type of file being compiled. Unfortunately this sometimes
|
||||
doesn't work, for example when using the aCC compiler on HP-UX. On
|
||||
systems like this you can use the CCACHE_EXTENSION option to override
|
||||
the default. On HP-UX set this environment variable to "i" if you use
|
||||
the aCC compiler.
|
||||
|
||||
dit(bf(CCACHE_STRIPC)) If you set the environment variable
|
||||
CCACHE_STRIPC then ccache will strip the -c option when invoking
|
||||
the preprocessor. This option is primarily for the Sun Workshop
|
||||
C++ compiler as without this option an unwarranted warning is displayed:
|
||||
CC: Warning: "-E" redefines product from "object" to "source (stdout)"
|
||||
when -E and -c is used together.
|
||||
|
||||
dit(bf(CCACHE_SWIG)) When using SWIG as the compiler and it does not
|
||||
have 'swig' in the executable name, then the CCACHE_SWIG environment
|
||||
variable needs to be set in order for ccache to work correctly with
|
||||
SWIG. The use of CCACHE_CPP2 is also recommended for SWIG due to some
|
||||
preprocessor quirks, however, use of CCACHE_CPP2 can often be skipped
|
||||
-- check your generated code with and without this option set. Known
|
||||
problems are using preprocessor directives within %inline blocks and
|
||||
the use of '#pragma SWIG'.
|
||||
|
||||
enddit()
|
||||
|
||||
manpagesection(CACHE SIZE MANAGEMENT)
|
||||
|
||||
By default ccache has a one gigabyte limit on the cache size and no
|
||||
maximum number of files. You can set a different limit using the
|
||||
"ccache -M" and "ccache -F" options, which set the size and number of
|
||||
files limits.
|
||||
|
||||
When these limits are reached ccache will reduce the cache to 20%
|
||||
below the numbers you specified in order to avoid doing the cache
|
||||
clean operation too often.
|
||||
|
||||
manpagesection(CACHE COMPRESSION)
|
||||
|
||||
By default on most platforms ccache will compress all files it puts
|
||||
into the cache
|
||||
using the zlib compression. While this involves a negligible
|
||||
performance slowdown, it significantly increases the number of files
|
||||
that fit in the cache. You can turn off compression setting the
|
||||
CCACHE_NOCOMPRESS environment variable.
|
||||
|
||||
manpagesection(HOW IT WORKS)
|
||||
|
||||
The basic idea is to detect when you are compiling exactly the same
|
||||
code a 2nd time and use the previously compiled output. You detect
|
||||
that it is the same code by forming a hash of:
|
||||
|
||||
itemization(
|
||||
it() the pre-processor output from running the compiler with -E
|
||||
it() the command line options
|
||||
it() the real compilers size and modification time
|
||||
it() any stderr output generated by the compiler
|
||||
)
|
||||
|
||||
These are hashed using md4 (a strong hash) and a cache file is formed
|
||||
based on that hash result. When the same compilation is done a second
|
||||
time ccache is able to supply the correct compiler output (including
|
||||
all warnings etc) from the cache.
|
||||
|
||||
ccache has been carefully written to always produce exactly the same
|
||||
compiler output that you would get without the cache. If you ever
|
||||
discover a case where ccache changes the output of your compiler then
|
||||
please let me know.
|
||||
|
||||
manpagesection(USING CCACHE WITH DISTCC)
|
||||
|
||||
distcc is a very useful program for distributing compilation across a
|
||||
range of compiler servers. It is often useful to combine distcc with
|
||||
ccache, so that compiles that are done are sped up by distcc, but that
|
||||
ccache avoids the compile completely where possible.
|
||||
|
||||
To use distcc with ccache I recommend using the CCACHE_PREFIX
|
||||
option. You just need to set the environment variable CCACHE_PREFIX to
|
||||
'distcc' and ccache will prefix the command line used with the
|
||||
compiler with the command 'distcc'.
|
||||
|
||||
manpagesection(SHARING A CACHE)
|
||||
|
||||
A group of developers can increase the cache hit rate by sharing a
|
||||
cache directory. The hard links however cause unwanted side effects,
|
||||
as all links to a cached file share the file's modification timestamp.
|
||||
This results in false dependencies to be triggered by timestamp-based
|
||||
build systems whenever another user links to an existing
|
||||
file. Typically, users will see that their libraries and binaries are
|
||||
relinked without reason. To share a cache without side effects, the
|
||||
following conditions need to be met:
|
||||
|
||||
itemization(
|
||||
it() Use the same bf(CCACHE_DIR) environment variable setting
|
||||
it() Unset the bf(CCACHE_HARDLINK) environment variable
|
||||
it() Make sure everyone sets the CCACHE_UMASK environment variable
|
||||
to 002, this ensures that cached files are accessible to everyone in
|
||||
the group.
|
||||
it() Make sure that all users have write permission in the entire
|
||||
cache directory (and that you trust all users of the shared cache).
|
||||
it() Make sure that the setgid bit is set on all directories in the
|
||||
cache. This tells the filesystem to inherit group ownership for new
|
||||
directories. The command "chmod g+s `find $CCACHE_DIR -type d`" might
|
||||
be useful for this.
|
||||
it() Set bf(CCACHE_NOCOMPRESS) for all users, if there are users with
|
||||
versions of ccache that do not support compression.
|
||||
)
|
||||
|
||||
manpagesection(HISTORY)
|
||||
|
||||
ccache was inspired by the compilercache shell script script written
|
||||
by Erik Thiele and I would like to thank him for an excellent piece of
|
||||
work. See
|
||||
url(http://www.erikyyy.de/compilercache/)(http://www.erikyyy.de/compilercache/)
|
||||
for the Erik's scripts.
|
||||
ccache-swig is a port of the original ccache with support added for use
|
||||
with SWIG.
|
||||
|
||||
I wrote ccache because I wanted to get a bit more speed out of a
|
||||
compiler cache and I wanted to remove some of the limitations of the
|
||||
shell-script version.
|
||||
|
||||
manpagesection(DIFFERENCES FROM COMPILERCACHE)
|
||||
|
||||
The biggest differences between Erik's compilercache script and ccache
|
||||
are:
|
||||
itemization(
|
||||
it() ccache is written in C, which makes it a bit faster (calling out to
|
||||
external programs is mostly what slowed down the scripts).
|
||||
it() ccache can automatically find the real compiler
|
||||
it() ccache keeps statistics on hits/misses
|
||||
it() ccache can do automatic cache management
|
||||
it() ccache can cache compiler output that includes warnings. In many
|
||||
cases this gives ccache a much higher cache hit rate.
|
||||
it() ccache can handle a much wider ranger of compiler options
|
||||
it() ccache avoids a double call to cpp on a cache miss
|
||||
)
|
||||
|
||||
manpagesection(CREDITS)
|
||||
|
||||
Thanks to the following people for their contributions to ccache
|
||||
itemization(
|
||||
it() Erik Thiele for the original compilercache script
|
||||
it() Luciano Rocha for the idea of compiling the pre-processor output
|
||||
to avoid a 2nd cpp pass
|
||||
it() Paul Russell for many suggestions and the debian packaging
|
||||
)
|
||||
|
||||
manpageauthor()
|
||||
|
||||
ccache was written by Andrew Tridgell
|
||||
url(http://samba.org/~tridge/)(http://samba.org/~tridge/).
|
||||
ccache was adapted to create ccache-swig for use with SWIG by William Fulton.
|
||||
|
||||
If you wish to report a problem or make a suggestion then please email
|
||||
the SWIG developers on the swig-devel mailing list, see
|
||||
url(http://www.swig.org/mail.html)(http://www.swig.org/mail.html)
|
||||
|
||||
ccache is released under the GNU General Public License version 2 or
|
||||
later. Please see the file COPYING for license details.
|
||||
|
||||
whenhtml(htmlcommand(
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
))
|
|
@ -0,0 +1 @@
|
|||
#define SWIG_VERSION "@PACKAGE_VERSION@"
|
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
Copyright (C) Andrew Tridgell 2002
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/*
|
||||
functions to cleanup the cache directory when it gets too large
|
||||
*/
|
||||
|
||||
#include "ccache.h"
|
||||
|
||||
static struct files {
|
||||
char *fname;
|
||||
time_t mtime;
|
||||
size_t size;
|
||||
} **files;
|
||||
static unsigned allocated;
|
||||
static unsigned num_files;
|
||||
static size_t total_size;
|
||||
static size_t total_files;
|
||||
static size_t size_threshold;
|
||||
static size_t files_threshold;
|
||||
|
||||
/* file comparison function to try to delete the oldest files first */
|
||||
static int files_compare(struct files **f1, struct files **f2)
|
||||
{
|
||||
if ((*f2)->mtime == (*f1)->mtime) {
|
||||
return strcmp((*f2)->fname, (*f1)->fname);
|
||||
}
|
||||
if ((*f2)->mtime > (*f1)->mtime) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* this builds the list of files in the cache */
|
||||
static void traverse_fn(const char *fname, struct stat *st)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (!S_ISREG(st->st_mode)) return;
|
||||
|
||||
p = str_basename(fname);
|
||||
if (strcmp(p, "stats") == 0) {
|
||||
free(p);
|
||||
return;
|
||||
}
|
||||
free(p);
|
||||
|
||||
if (num_files == allocated) {
|
||||
allocated = 10000 + num_files*2;
|
||||
files = (struct files **)x_realloc(files,
|
||||
sizeof(struct files *)*allocated);
|
||||
}
|
||||
|
||||
files[num_files] = (struct files *)x_malloc(sizeof(struct files));
|
||||
files[num_files]->fname = x_strdup(fname);
|
||||
files[num_files]->mtime = st->st_mtime;
|
||||
files[num_files]->size = file_size(st) / 1024;
|
||||
total_size += files[num_files]->size;
|
||||
num_files++;
|
||||
}
|
||||
|
||||
/* sort the files we've found and delete the oldest ones until we are
|
||||
below the thresholds */
|
||||
static void sort_and_clean(size_t minfiles)
|
||||
{
|
||||
unsigned i;
|
||||
size_t adjusted_minfiles = minfiles;
|
||||
|
||||
if (num_files > 1) {
|
||||
/* sort in ascending data order */
|
||||
qsort(files, num_files, sizeof(struct files *),
|
||||
(COMPAR_FN_T)files_compare);
|
||||
}
|
||||
/* ensure newly cached files (minfiles) are kept - instead of matching
|
||||
the filenames of those newly cached, a faster and simpler approach
|
||||
assumes these are the most recent in the cache and if any other
|
||||
cached files have an identical time stamp, they will also be kept -
|
||||
this approach would not be needed if the cleanup was done at exit. */
|
||||
if (minfiles != 0 && minfiles < num_files) {
|
||||
unsigned minfiles_index = num_files - minfiles;
|
||||
time_t minfiles_time = files[minfiles_index]->mtime;
|
||||
for (i=1; i<=minfiles_index; i++) {
|
||||
if (files[minfiles_index-i]->mtime == minfiles_time)
|
||||
adjusted_minfiles++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* delete enough files to bring us below the threshold */
|
||||
for (i=0;i<num_files; i++) {
|
||||
if ((size_threshold==0 || total_size < size_threshold) &&
|
||||
(files_threshold==0 || (num_files-i) < files_threshold)) break;
|
||||
|
||||
if (adjusted_minfiles != 0 && num_files-i <= adjusted_minfiles)
|
||||
break;
|
||||
|
||||
if (unlink(files[i]->fname) != 0 && errno != ENOENT) {
|
||||
fprintf(stderr, "unlink %s - %s\n",
|
||||
files[i]->fname, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
total_size -= files[i]->size;
|
||||
}
|
||||
|
||||
total_files = num_files - i;
|
||||
}
|
||||
|
||||
/* cleanup in one cache subdir */
|
||||
void cleanup_dir(const char *dir, size_t maxfiles, size_t maxsize, size_t minfiles)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
size_threshold = maxsize * LIMIT_MULTIPLE;
|
||||
files_threshold = maxfiles * LIMIT_MULTIPLE;
|
||||
|
||||
num_files = 0;
|
||||
total_size = 0;
|
||||
|
||||
/* build a list of files */
|
||||
traverse(dir, traverse_fn);
|
||||
|
||||
/* clean the cache */
|
||||
sort_and_clean(minfiles);
|
||||
|
||||
stats_set_sizes(dir, total_files, total_size);
|
||||
|
||||
/* free it up */
|
||||
for (i=0;i<num_files;i++) {
|
||||
free(files[i]->fname);
|
||||
free(files[i]);
|
||||
files[i] = NULL;
|
||||
}
|
||||
if (files) free(files);
|
||||
allocated = 0;
|
||||
files = NULL;
|
||||
|
||||
num_files = 0;
|
||||
total_size = 0;
|
||||
}
|
||||
|
||||
/* cleanup in all cache subdirs */
|
||||
void cleanup_all(const char *dir)
|
||||
{
|
||||
unsigned counters[STATS_END];
|
||||
char *dname, *sfile;
|
||||
int i;
|
||||
|
||||
for (i=0;i<=0xF;i++) {
|
||||
x_asprintf(&dname, "%s/%1x", dir, i);
|
||||
x_asprintf(&sfile, "%s/%1x/stats", dir, i);
|
||||
|
||||
memset(counters, 0, sizeof(counters));
|
||||
stats_read(sfile, counters);
|
||||
|
||||
cleanup_dir(dname,
|
||||
counters[STATS_MAXFILES],
|
||||
counters[STATS_MAXSIZE],
|
||||
0);
|
||||
free(dname);
|
||||
free(sfile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* traverse function for wiping files */
|
||||
static void wipe_fn(const char *fname, struct stat *st)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (!S_ISREG(st->st_mode)) return;
|
||||
|
||||
p = str_basename(fname);
|
||||
if (strcmp(p, "stats") == 0) {
|
||||
free(p);
|
||||
return;
|
||||
}
|
||||
free(p);
|
||||
|
||||
unlink(fname);
|
||||
}
|
||||
|
||||
|
||||
/* wipe all cached files in all subdirs */
|
||||
void wipe_all(const char *dir)
|
||||
{
|
||||
char *dname;
|
||||
int i;
|
||||
|
||||
for (i=0;i<=0xF;i++) {
|
||||
x_asprintf(&dname, "%s/%1x", dir, i);
|
||||
traverse(dir, wipe_fn);
|
||||
free(dname);
|
||||
}
|
||||
|
||||
/* and fix the counters */
|
||||
cleanup_all(dir);
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to 1 if you would like to have zlib compression for ccache. */
|
||||
#undef ENABLE_ZLIB
|
||||
|
||||
/* Define to 1 if you have the `asprintf' function. */
|
||||
#undef HAVE_ASPRINTF
|
||||
|
||||
/* */
|
||||
#undef HAVE_C99_VSNPRINTF
|
||||
|
||||
/* */
|
||||
#undef HAVE_COMPAR_FN_T
|
||||
|
||||
/* Define to 1 if you have the <ctype.h> header file. */
|
||||
#undef HAVE_CTYPE_H
|
||||
|
||||
/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
#undef HAVE_DIRENT_H
|
||||
|
||||
/* Define to 1 if you have the `gethostname' function. */
|
||||
#undef HAVE_GETHOSTNAME
|
||||
|
||||
/* Define to 1 if you have the `getpwuid' function. */
|
||||
#undef HAVE_GETPWUID
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `mkstemp' function. */
|
||||
#undef HAVE_MKSTEMP
|
||||
|
||||
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
|
||||
#undef HAVE_NDIR_H
|
||||
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
#undef HAVE_PWD_H
|
||||
|
||||
/* Define to 1 if you have the `realpath' function. */
|
||||
#undef HAVE_REALPATH
|
||||
|
||||
/* Define to 1 if you have the `snprintf' function. */
|
||||
#undef HAVE_SNPRINTF
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
#undef HAVE_SYS_DIR_H
|
||||
|
||||
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
#undef HAVE_SYS_NDIR_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
|
||||
#undef HAVE_SYS_WAIT_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if you have the `utimes' function. */
|
||||
#undef HAVE_UTIMES
|
||||
|
||||
/* Define to 1 if you have the `vasprintf' function. */
|
||||
#undef HAVE_VASPRINTF
|
||||
|
||||
/* Define to 1 if you have the `vsnprintf' function. */
|
||||
#undef HAVE_VSNPRINTF
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define my program name */
|
||||
#undef PROGRAM_NAME
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
|
||||
#undef TIME_WITH_SYS_TIME
|
||||
|
||||
/* Define _GNU_SOURCE so that we get all necessary prototypes */
|
||||
#undef _GNU_SOURCE
|
|
@ -0,0 +1,3 @@
|
|||
#if !defined(PROGRAM_NAME)
|
||||
#define PROGRAM_NAME "@PROGRAM_NAME@.exe"
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,102 @@
|
|||
dnl Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_INIT([ccache-swig], [0.0]) # Get version from SWIG in ccache_swig_config.h.in
|
||||
AC_PREREQ(2.52)
|
||||
AC_CONFIG_SRCDIR([ccache.h])
|
||||
|
||||
AC_MSG_NOTICE([Configuring ccache])
|
||||
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_CONFIG_FILES([config_win32.h])
|
||||
|
||||
dnl Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_PROG_INSTALL
|
||||
AC_ARG_PROGRAM # for program_transform_name
|
||||
|
||||
AC_SUBST(PROGRAM_NAME)
|
||||
if test "x$program_prefix" != "xNONE" -a "x$program_prefix" != "x"
|
||||
then
|
||||
PROGRAM_NAME="$program_prefix$PACKAGE_NAME"
|
||||
else
|
||||
PROGRAM_NAME="$PACKAGE_NAME"
|
||||
fi
|
||||
if test "x$program_suffix" != "xNONE" -a "x$program_suffix" != "x"
|
||||
then
|
||||
PROGRAM_NAME="$PROGRAM_NAME$program_suffix"
|
||||
fi
|
||||
|
||||
AC_DEFINE_UNQUOTED(PROGRAM_NAME, "$PROGRAM_NAME", [Define my program name])
|
||||
|
||||
AC_DEFINE([_GNU_SOURCE], 1,
|
||||
[Define _GNU_SOURCE so that we get all necessary prototypes])
|
||||
|
||||
# If GCC, turn on warnings.
|
||||
if test "x$GCC" = "xyes"
|
||||
then
|
||||
CFLAGS="$CFLAGS -Wall -W"
|
||||
else
|
||||
CFLAGS="$CFLAGS -O"
|
||||
fi
|
||||
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_TIME
|
||||
AC_HEADER_SYS_WAIT
|
||||
|
||||
AC_CHECK_HEADERS(ctype.h strings.h stdlib.h string.h pwd.h sys/time.h)
|
||||
|
||||
AC_CHECK_FUNCS(realpath snprintf vsnprintf vasprintf asprintf mkstemp)
|
||||
AC_CHECK_FUNCS(gethostname getpwuid)
|
||||
AC_CHECK_FUNCS(utimes)
|
||||
|
||||
AC_CACHE_CHECK([for compar_fn_t in stdlib.h],ccache_cv_COMPAR_FN_T, [
|
||||
AC_TRY_COMPILE(
|
||||
[#include <stdlib.h>],
|
||||
[
|
||||
void test_fn(void) { qsort(NULL, 0, 0, (__compar_fn_t)NULL); }
|
||||
],
|
||||
ccache_cv_COMPAR_FN_T=yes,ccache_cv_COMPAR_FN_T=no)])
|
||||
if test x"$ccache_cv_COMPAR_FN_T" = x"yes"; then
|
||||
AC_DEFINE(HAVE_COMPAR_FN_T, 1, [ ])
|
||||
fi
|
||||
|
||||
dnl Note: This could be replaced by AC_FUNC_SNPRINTF() in the autoconf macro archive
|
||||
AC_CACHE_CHECK([for C99 vsnprintf],ccache_cv_HAVE_C99_VSNPRINTF,[
|
||||
AC_TRY_RUN([
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
void foo(const char *format, ...) {
|
||||
va_list ap;
|
||||
int len;
|
||||
char buf[5];
|
||||
|
||||
va_start(ap, format);
|
||||
len = vsnprintf(0, 0, format, ap);
|
||||
va_end(ap);
|
||||
if (len != 5) exit(1);
|
||||
|
||||
if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(1);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
main() { foo("hello"); }
|
||||
],
|
||||
ccache_cv_HAVE_C99_VSNPRINTF=yes,ccache_cv_HAVE_C99_VSNPRINTF=no,ccache_cv_HAVE_C99_VSNPRINTF=cross)])
|
||||
if test x"$ccache_cv_HAVE_C99_VSNPRINTF" = x"yes"; then
|
||||
AC_DEFINE(HAVE_C99_VSNPRINTF, 1, [ ])
|
||||
fi
|
||||
|
||||
dnl Check for zlib.
|
||||
dnl Note: This could be replaced by CHECK_ZLIB() in the autoconf macro archive
|
||||
AC_ARG_ENABLE([zlib],
|
||||
AS_HELP_STRING([--enable-zlib], [enable zlib support for ccache compression]),,
|
||||
[enable_zlib=yes])
|
||||
|
||||
if test x"$enable_zlib" = x"yes"; then
|
||||
AC_CHECK_HEADER(zlib.h, AC_CHECK_LIB(z, gzdopen, [LIBS="-lz $LIBS"
|
||||
AC_DEFINE([ENABLE_ZLIB], 1, [Define to 1 if you would like to have zlib compression for ccache.]) ] ))
|
||||
fi
|
||||
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_OUTPUT
|
|
@ -0,0 +1,22 @@
|
|||
ccache (2.4-8) unstable; urgency=high
|
||||
|
||||
zlib compression is now enabled by default in order to increase the amount
|
||||
of object files that can fit in the cache.
|
||||
|
||||
The impact on performance is supposed to be almost negligible
|
||||
(see http://www.gustaebel.de/lars/ccache/). If you do want to disable
|
||||
it however, simply export the CCACHE_NOCOMPRESS environment variable.
|
||||
|
||||
Note that a zlib-enabled ccache will still read your existing
|
||||
uncompressed cache. If you want to compress/uncompress your cache,
|
||||
see the manage-cache.sh script under /usr/share/doc/ccache/examples/.
|
||||
|
||||
-- Francois Marier <francois@debian.org> Sun, 20 May 2007 19:45:07 +1200
|
||||
|
||||
ccache (2.4-1) unstable; urgency=low
|
||||
|
||||
* This release changes the hash input slighly, so you will probably find
|
||||
that you will not get any hits against your existing cache when you
|
||||
upgrade.
|
||||
|
||||
-- Francois Marier <francois@debian.org> Sat, 11 Jun 2005 13:54:33 -0400
|
|
@ -0,0 +1,59 @@
|
|||
Installing ccache
|
||||
-----------------
|
||||
|
||||
The recommended way to use this with Debian is to either create "cc"
|
||||
and "gcc" symlinks to /usr/bin/ccache in your private bin directory
|
||||
(which must be before the real cc and gcc in your path), or use
|
||||
CC="ccache gcc" on the make command line.
|
||||
|
||||
Another option is to just prepend /usr/lib/ccache in your PATH
|
||||
environment variable, like
|
||||
|
||||
export PATH="/usr/lib/ccache:$PATH"
|
||||
|
||||
Note that ccache works with both native and cross compilers.
|
||||
|
||||
Ignoring whitespace
|
||||
-------------------
|
||||
|
||||
If you wish to set up ccache so that it ignores blank lines, have a
|
||||
look at the CCACHE_UNIFY option. However, please note that this
|
||||
option is off by default since the reported line numbers may not
|
||||
match the source files anymore.
|
||||
|
||||
|
||||
NFS Issues
|
||||
----------
|
||||
|
||||
(from John Coiner <john.coiner@amd.com> on the ccache mailing list)
|
||||
|
||||
When CCache creates a hardlinked output file, it calls utime() to update
|
||||
the timestamp on the object, so that Make realizes that the object has
|
||||
changed.
|
||||
|
||||
On NFS, utime() has no coherency guarantee, AFAIK. When utime() runs on
|
||||
host A, and our parallel implementation of Make is running on host B,
|
||||
sometimes Make doesn't see the new timestamp soon enough -- and neglects
|
||||
to relink the final binary. That's a one-way ticket to Silent Mysterious
|
||||
Failure Town.
|
||||
|
||||
Instead of relying on the object file timestamp, we create a dummy file
|
||||
with a reliable timestamp:
|
||||
|
||||
objs/foo.o objs/foo.o.built :
|
||||
if ( ccache gcc -o foo.o -c foo.c ) ; \
|
||||
then touch objs/foo.o.built ; \
|
||||
else exit 1; \
|
||||
fi
|
||||
|
||||
binary : objs/foo.o.built
|
||||
gcc -o binary objs/foo.o
|
||||
|
||||
NFS does make a coherency guarantee, that if a file is written and
|
||||
close()d on host A, and subsequently open()ed on host B, that the second
|
||||
open() will reflect all modifications and attributes from the close().
|
||||
Since Make does open() when checking timestamps, and the dummy file is
|
||||
close()d when it's created, the binary will always relink after the
|
||||
object is recompiled.
|
||||
|
||||
-- Francois Marier <francois@debian.org> Sun, 20 May 2007 17:35:36 +1200
|
|
@ -0,0 +1,221 @@
|
|||
ccache (2.4-15) unstable; urgency=low
|
||||
|
||||
* Add a new patch which improve the consistency of timestamps on cached
|
||||
objects to make sure clean-up is based on least recently used objects.
|
||||
* Patch the set_limit call so that non-writable cache directories return
|
||||
an error when attempting to size the max(files|size) (closes: #332527)
|
||||
|
||||
-- Francois Marier <francois@debian.org> Sun, 13 Apr 2008 15:07:05 +1200
|
||||
|
||||
ccache (2.4-14) unstable; urgency=low
|
||||
|
||||
* Mention the long options everywhere in the manpage
|
||||
* Merge Gentoo patches:
|
||||
- respect user's LDFLAGS
|
||||
- use utimes() for timestamp if possible
|
||||
|
||||
-- Francois Marier <francois@debian.org> Sun, 23 Mar 2008 16:30:11 +1300
|
||||
|
||||
ccache (2.4-13) unstable; urgency=low
|
||||
|
||||
* Update CACHEDIR.TAG patch to avoid creating the tag file when the
|
||||
CCACHE_READONLY environment variable is set. (closes: #464356)
|
||||
* Mention the GNU-style long options in the manpage
|
||||
|
||||
-- Francois Marier <francois@debian.org> Thu, 07 Feb 2008 10:50:42 +1300
|
||||
|
||||
ccache (2.4-12) unstable; urgency=low
|
||||
|
||||
* Add symlink for gcc 4.3 (closes: #463590)
|
||||
* Add support for the CACHEDIR.TAG spec, thanks to Karl Chen.
|
||||
(see http://www.brynosaurus.com/cachedir/)
|
||||
* Fix hyphens in manpage (lintian notice)
|
||||
* Bump Standards-Version up to 3.7.3 (no changes)
|
||||
* Bump debhelper compatibility to 6
|
||||
|
||||
-- Francois Marier <francois@debian.org> Sat, 02 Feb 2008 10:37:22 +1300
|
||||
|
||||
ccache (2.4-11) unstable; urgency=low
|
||||
|
||||
* Add the collab-maint repo to debian/control
|
||||
|
||||
-- Francois Marier <francois@debian.org> Tue, 20 Nov 2007 15:26:37 +1300
|
||||
|
||||
ccache (2.4-10) unstable; urgency=low
|
||||
|
||||
* Document where the patches are from in debian/patches/CREDITS
|
||||
* debian/rules:
|
||||
- Fixed "make distclean" lintian warning
|
||||
- Removed commented-out entries
|
||||
* Set debhelper compatibility to 5
|
||||
* Add homepage field in debian/control
|
||||
* Add symlinks for MinGW (closes: #445782)
|
||||
* Bump the version to 5 in the debhelper dependency
|
||||
|
||||
-- Francois Marier <francois@debian.org> Fri, 19 Oct 2007 16:04:37 +1300
|
||||
|
||||
ccache (2.4-9) unstable; urgency=low
|
||||
|
||||
* Add a symlink for gcc 4.2 (closes: #431007)
|
||||
* Fix dependencies when using -o (closes: #217713)
|
||||
|
||||
-- Francois Marier <francois@debian.org> Sat, 30 Jun 2007 17:58:44 +1200
|
||||
|
||||
ccache (2.4-8) unstable; urgency=low
|
||||
|
||||
* Enable zlib compression of the cache by default (closes: #409848).
|
||||
Thanks to Sami Liedes for suggesting this.
|
||||
* Disable ccache when profiling (closes: #215849).
|
||||
Thanks to Ted Percival for the Patch.
|
||||
* Fix NFS renaming issues and add instructions to the README.
|
||||
Thanks to John Coiner and instructions.
|
||||
* Put all patches in debian/patches and apply them at build time.
|
||||
|
||||
-- Francois Marier <francois@debian.org> Sun, 20 May 2007 19:42:34 +1200
|
||||
|
||||
ccache (2.4-7) unstable; urgency=low
|
||||
|
||||
* Use the real compiler when HOME is not set (closes: #396350)
|
||||
* Include user script under doc/examples (closes: #392435)
|
||||
Thanks to Behan Webster!
|
||||
* Add support for GNU --long options (closes: #297126)
|
||||
|
||||
-- Francois Marier <francois@debian.org> Sat, 18 Nov 2006 00:50:59 -0500
|
||||
|
||||
ccache (2.4-6) unstable; urgency=low
|
||||
|
||||
* Include symlinks for gcc 4.1 (closes: #372838)
|
||||
* Update watch file
|
||||
|
||||
-- Francois Marier <francois@debian.org> Tue, 13 Jun 2006 22:17:37 -0400
|
||||
|
||||
ccache (2.4-5) unstable; urgency=low
|
||||
|
||||
* Document the fact that cross-compiling is supported (closes: #349221)
|
||||
* Bump Standards-Version up to 3.7.2 (no changes)
|
||||
|
||||
-- Francois Marier <francois@debian.org> Sun, 4 Jun 2006 01:20:07 -0400
|
||||
|
||||
ccache (2.4-4) unstable; urgency=low
|
||||
|
||||
* Mention another way to use ccache in README.Debian (thanks to Benjamin
|
||||
Drieu for the suggestion) (closes: #267632)
|
||||
* Update FSF address
|
||||
* Fix watch file
|
||||
|
||||
-- Francois Marier <francois@debian.org> Sat, 26 Nov 2005 00:15:13 -0500
|
||||
|
||||
ccache (2.4-3) unstable; urgency=low
|
||||
|
||||
* Actually use the configuration flags in debian/rules
|
||||
* Bump Standards-Version up to 3.6.2 (no changes)
|
||||
|
||||
-- Francois Marier <francois@debian.org> Sun, 26 Jun 2005 13:33:19 -0400
|
||||
|
||||
ccache (2.4-2) unstable; urgency=low
|
||||
|
||||
* Add gcc and g++ symlinks to /usr/lib/ccache (closes: #313490)
|
||||
* Remove invalid entry from Depends
|
||||
|
||||
-- Francois Marier <francois@debian.org> Wed, 15 Jun 2005 20:51:03 -0400
|
||||
|
||||
ccache (2.4-1) unstable; urgency=low
|
||||
|
||||
* New maintainer (closes: #312867)
|
||||
* New upstream version: (closes: #273753, #239640)
|
||||
- New CCACHE_READONLY and CCACHE_TEMPDIR options
|
||||
- Fixed handling of hard-linked compilers on AIX
|
||||
- Fixed handling of HOME environment variable (closes: #299880)
|
||||
- Show cache directory in stats output
|
||||
* Fix copyright file
|
||||
* Add 'distcc' to Suggests (closes: #269158)
|
||||
* Add a note about whitespace in README.Debian (closes: #229116)
|
||||
* Update rules to add symmlinks for gcc 3.4 & 4.0 (closes: #261177)
|
||||
* Acknowledge NMUs (closes: #200185, #177129, #174417)
|
||||
|
||||
-- Francois Marier <francois@debian.org> Sun, 12 Jun 2005 12:05:34 -0400
|
||||
|
||||
ccache (2.3-1.1) unstable; urgency=low
|
||||
|
||||
* Non-maintainer upload during BSP
|
||||
* Re-apply patch for
|
||||
#200185 ccache: Incorrect symlinks in /usr/lib/ccache
|
||||
(Closes: #200185)
|
||||
|
||||
-- Frank Lichtenheld <djpig@debian.org> Fri, 19 Mar 2004 11:14:50 +0100
|
||||
|
||||
ccache (2.3-1) unstable; urgency=low
|
||||
|
||||
* New upstream release: obsoletes existing caches.
|
||||
* Tweak package description in arbitrary way (closes: #181721)
|
||||
|
||||
-- Paul Russell <prussell@debian.org> Mon, 29 Sep 2003 02:53:20 +0200
|
||||
|
||||
ccache (2.2-2) unstable; urgency=low
|
||||
|
||||
* Insert more symlinks in ccache dir (closes: #197468)
|
||||
|
||||
-- Paul Russell <prussell@debian.org> Mon, 16 Jun 2003 10:52:50 +0100
|
||||
|
||||
ccache (2.2-1) unstable; urgency=low
|
||||
|
||||
* New upstream release (closes: #150755)
|
||||
* Insert more symlinks in ccache dir (closes: #144462)
|
||||
|
||||
-- Paul Russell <prussell@debian.org> Mon, 17 Feb 2003 07:19:36 +0100
|
||||
|
||||
ccache (2.1.1-2) unstable; urgency=low
|
||||
|
||||
* Restored /usr/lib/ccache symlinks (closes: #179393)
|
||||
* Fixed manpage typo (closes: #179564)
|
||||
* With thanks to Andreas Rottmann.
|
||||
|
||||
-- Paul Russell <prussell@debian.org> Wed, 5 Feb 2003 10:01:10 +0100
|
||||
|
||||
ccache (2.1.1-1) unstable; urgency=low
|
||||
|
||||
* NMU (with maintainer consent).
|
||||
* New upstream release (closes: #174417, #177129).
|
||||
* debian/control:
|
||||
+ Build-Depend on and use dephelper 4 (DH_COMPAT = 4).
|
||||
+ Bumped Standards-Version to 3.5.8.
|
||||
+ No full stop on short package description (fixes linda warning).
|
||||
* debian/copright:
|
||||
+ Make lintian feel comfortable; fixes warnings:
|
||||
- copyright-should-refer-to-common-license-file-for-gpl
|
||||
- copyright-lists-upstream-authors-with-dh_make-boilerplate
|
||||
* Built with g++ 3.2 :-).
|
||||
|
||||
-- Andreas Rottmann <rotty@debian.org> Thu, 16 Jan 2003 11:42:38 +0100
|
||||
|
||||
ccache (1.9-1) unstable; urgency=low
|
||||
|
||||
* New upstream release (closes: #144920)
|
||||
|
||||
-- Paul Russell <prussell@debian.org> Mon, 13 May 2002 10:01:09 +0200
|
||||
|
||||
ccache (1.8-1) unstable; urgency=low
|
||||
|
||||
* New upstream release (closes: #145401)
|
||||
|
||||
-- Paul Russell <prussell@debian.org> Fri, 3 May 2002 02:26:32 +0200
|
||||
|
||||
ccache (1.7-1) unstable; urgency=low
|
||||
|
||||
* New upstream release
|
||||
* Install symlinks in /usr/lib/ccache (closes: #141337)
|
||||
|
||||
-- Paul Russell <prussell@debian.org> Wed, 10 Apr 2002 17:51:21 +0200
|
||||
|
||||
ccache (1.4-1) unstable; urgency=low
|
||||
|
||||
* New upstream release
|
||||
|
||||
-- Paul Russell <prussell@debian.org> Wed, 3 Apr 2002 03:41:46 +0200
|
||||
|
||||
ccache (1.2-1) unstable; urgency=low
|
||||
|
||||
* Initial Release.
|
||||
|
||||
-- Paul Russell <prussell@debian.org> Sun, 31 Mar 2002 14:08:57 +0200
|
||||
|
|
@ -0,0 +1 @@
|
|||
6
|
|
@ -0,0 +1,20 @@
|
|||
Source: ccache
|
||||
Section: devel
|
||||
Priority: optional
|
||||
Maintainer: Francois Marier <francois@debian.org>
|
||||
Build-Depends: debhelper (>> 6), autotools-dev, zlib1g-dev
|
||||
Standards-Version: 3.7.3
|
||||
Homepage: http://ccache.samba.org
|
||||
Vcs-Svn: svn://svn.debian.org/svn/collab-maint/deb-maint/ccache/
|
||||
Vcs-Browser: http://svn.debian.org/wsvn/collab-maint/deb-maint/ccache/
|
||||
|
||||
Package: ccache
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}
|
||||
Suggests: distcc
|
||||
Description: Compiler results cacher, for fast recompiles
|
||||
ccache is a compiler cache. It speeds up re-compilation of C/C++ code
|
||||
by caching previous compiles and detecting when the same compile is
|
||||
being done again.
|
||||
.
|
||||
This is similar to, but faster than, the compilercache package.
|
|
@ -0,0 +1,29 @@
|
|||
This package was debianized by Paul Russell <prussell@debian.org> on
|
||||
Sun, 31 Mar 2002 14:08:57 +0200.
|
||||
|
||||
It was downloaded from http://ccache.samba.org/ftp/ccache/
|
||||
|
||||
The ccache-zlib patch was downloaded from http://www.gustaebel.de/lars/ccache/
|
||||
|
||||
Upstream Author: Andrew Tridgell <tridge@samba.org>
|
||||
|
||||
Copyright: 2002-2005 Andrew Tridgell <tridge@samba.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301, USA
|
||||
|
||||
You are free to distribute this software under the terms of the GNU General
|
||||
Public License. On Debian systems, the complete text of the GNU General
|
||||
Public License can be found in /usr/share/common-licenses/GPL file.
|
|
@ -0,0 +1,3 @@
|
|||
usr/bin
|
||||
usr/lib/ccache
|
||||
usr/share/man/man1
|
|
@ -0,0 +1 @@
|
|||
README
|
|
@ -0,0 +1,2 @@
|
|||
debian/update-ccache
|
||||
manage-cache.sh
|
|
@ -0,0 +1,100 @@
|
|||
--- ccache.c
|
||||
+++ ccache.c
|
||||
@@ -836,6 +836,13 @@
|
||||
{
|
||||
/* find the real compiler */
|
||||
find_compiler(argc, argv);
|
||||
+
|
||||
+ /* use the real compiler if HOME is not set */
|
||||
+ if (!cache_dir) {
|
||||
+ cc_log("Unable to determine home directory\n");
|
||||
+ cc_log("ccache is disabled\n");
|
||||
+ failed();
|
||||
+ }
|
||||
|
||||
/* we might be disabled */
|
||||
if (getenv("CCACHE_DISABLE")) {
|
||||
@@ -895,6 +902,13 @@
|
||||
printf("-V print version number\n");
|
||||
}
|
||||
|
||||
+static void check_cache_dir(void)
|
||||
+{
|
||||
+ if (!cache_dir) {
|
||||
+ fatal("Unable to determine home directory");
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/* the main program when not doing a compile */
|
||||
static int ccache_main(int argc, char *argv[])
|
||||
{
|
||||
@@ -914,31 +928,37 @@
|
||||
exit(0);
|
||||
|
||||
case 's':
|
||||
+ check_cache_dir();
|
||||
stats_summary();
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
+ check_cache_dir();
|
||||
cleanup_all(cache_dir);
|
||||
printf("Cleaned cache\n");
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
+ check_cache_dir();
|
||||
wipe_all(cache_dir);
|
||||
printf("Cleared cache\n");
|
||||
break;
|
||||
|
||||
case 'z':
|
||||
+ check_cache_dir();
|
||||
stats_zero();
|
||||
printf("Statistics cleared\n");
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
+ check_cache_dir();
|
||||
v = atoi(optarg);
|
||||
stats_set_limits(v, -1);
|
||||
printf("Set cache file limit to %u\n", (unsigned)v);
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
+ check_cache_dir();
|
||||
v = value_units(optarg);
|
||||
stats_set_limits(-1, v);
|
||||
printf("Set cache size limit to %uk\n", (unsigned)v);
|
||||
@@ -983,7 +1003,10 @@
|
||||
|
||||
cache_dir = getenv("CCACHE_DIR");
|
||||
if (!cache_dir) {
|
||||
- x_asprintf(&cache_dir, "%s/.ccache", get_home_directory());
|
||||
+ const char *home_directory = get_home_directory();
|
||||
+ if (home_directory) {
|
||||
+ x_asprintf(&cache_dir, "%s/.ccache", home_directory);
|
||||
+ }
|
||||
}
|
||||
|
||||
temp_dir = getenv("CCACHE_TEMPDIR");
|
||||
@@ -1023,7 +1046,7 @@
|
||||
}
|
||||
|
||||
/* make sure the cache dir exists */
|
||||
- if (create_dir(cache_dir) != 0) {
|
||||
+ if (cache_dir && (create_dir(cache_dir) != 0)) {
|
||||
fprintf(stderr,"ccache: failed to create %s (%s)\n",
|
||||
cache_dir, strerror(errno));
|
||||
exit(1);
|
||||
--- util.c
|
||||
+++ util.c
|
||||
@@ -448,7 +448,7 @@
|
||||
}
|
||||
}
|
||||
#endif
|
||||
- fatal("Unable to determine home directory");
|
||||
+ cc_log("Unable to determine home directory");
|
||||
return NULL;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,133 @@
|
|||
Index: ccache.c
|
||||
===================================================================
|
||||
--- ccache.c (révision 7695)
|
||||
+++ ccache.c (copie de travail)
|
||||
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "ccache.h"
|
||||
+#include <getopt.h>
|
||||
|
||||
/* the base cache directory */
|
||||
char *cache_dir = NULL;
|
||||
@@ -885,14 +886,14 @@
|
||||
printf("\tcompiler [compile options] (via symbolic link)\n");
|
||||
printf("\nOptions:\n");
|
||||
|
||||
- printf("-s show statistics summary\n");
|
||||
- printf("-z zero statistics\n");
|
||||
- printf("-c run a cache cleanup\n");
|
||||
- printf("-C clear the cache completely\n");
|
||||
- printf("-F <maxfiles> set maximum files in cache\n");
|
||||
- printf("-M <maxsize> set maximum size of cache (use G, M or K)\n");
|
||||
- printf("-h this help page\n");
|
||||
- printf("-V print version number\n");
|
||||
+ printf("-s, --show-stats show statistics summary\n");
|
||||
+ printf("-z, --zero-stats zero statistics\n");
|
||||
+ printf("-c, --cleanup run a cache cleanup\n");
|
||||
+ printf("-C, --clear clear the cache completely\n");
|
||||
+ printf("-F <n>, --max-files=<n> set maximum files in cache\n");
|
||||
+ printf("-M <n>, --max-size=<n> set maximum size of cache (use G, M or K)\n");
|
||||
+ printf("-h, --help this help page\n");
|
||||
+ printf("-V, --version print version number\n");
|
||||
}
|
||||
|
||||
/* the main program when not doing a compile */
|
||||
@@ -901,7 +902,21 @@
|
||||
int c;
|
||||
size_t v;
|
||||
|
||||
- while ((c = getopt(argc, argv, "hszcCF:M:V")) != -1) {
|
||||
+ static struct option long_options[] =
|
||||
+ {
|
||||
+ {"show-stats", no_argument, 0, 's'},
|
||||
+ {"zero-stats", no_argument, 0, 'z'},
|
||||
+ {"cleanup", no_argument, 0, 'c'},
|
||||
+ {"clear", no_argument, 0, 'C'},
|
||||
+ {"max-files", required_argument, 0, 'F'},
|
||||
+ {"max-size", required_argument, 0, 'M'},
|
||||
+ {"help", no_argument, 0, 'h'},
|
||||
+ {"version", no_argument, 0, 'V'},
|
||||
+ {0, 0, 0, 0}
|
||||
+ };
|
||||
+ int option_index = 0;
|
||||
+
|
||||
+ while ((c = getopt_long(argc, argv, "hszcCF:M:V", long_options, &option_index)) != -1) {
|
||||
switch (c) {
|
||||
case 'V':
|
||||
printf("ccache version %s\n", CCACHE_VERSION);
|
||||
Index: ccache.1
|
||||
===================================================================
|
||||
--- ccache.1 (révision 7695)
|
||||
+++ ccache.1 (copie de travail)
|
||||
@@ -23,14 +23,14 @@
|
||||
.nf
|
||||
|
||||
|
||||
--s show statistics summary
|
||||
--z zero statistics
|
||||
--c run a cache cleanup
|
||||
--C clear the cache completely
|
||||
--F <maxfiles> set maximum files in cache
|
||||
--M <maxsize> set maximum size of cache (use G, M or K)
|
||||
--h this help page
|
||||
--V print version number
|
||||
+\-s, \-\-show-stats show statistics summary
|
||||
+\-z, \-\-zero-stats zero statistics
|
||||
+\-c, \-\-cleanup run a cache cleanup
|
||||
+\-C, \-\-clear clear the cache completely
|
||||
+\-F <n>, \-\-max-files=<n> set maximum files in cache
|
||||
+\-M <n>, \-\-max-size=<n> set maximum size of cache (use G, M or K)
|
||||
+\-h, \-\-help this help page
|
||||
+\-V, \-\-version print version number
|
||||
|
||||
.fi
|
||||
|
||||
@@ -43,22 +43,22 @@
|
||||
normal compiler options apply and you should refer to your compilers
|
||||
documentation\&.
|
||||
.PP
|
||||
-.IP "\fB-h\fP"
|
||||
+.IP "\fB-h, --help\fP"
|
||||
Print a options summary page
|
||||
.IP
|
||||
-.IP "\fB-s\fP"
|
||||
+.IP "\fB-s, --show-stats\fP"
|
||||
Print the current statistics summary for the cache\&. The
|
||||
statistics are stored spread across the subdirectories of the
|
||||
cache\&. Using "ccache -s" adds up the statistics across all
|
||||
subdirectories and prints the totals\&.
|
||||
.IP
|
||||
-.IP "\fB-z\fP"
|
||||
+.IP "\fB-z, --zero-stats\fP"
|
||||
Zero the cache statistics\&.
|
||||
.IP
|
||||
-.IP "\fB-V\fP"
|
||||
+.IP "\fB-V, --version\fP"
|
||||
Print the ccache version number
|
||||
.IP
|
||||
-.IP "\fB-c\fP"
|
||||
+.IP "\fB-c, --cleanup\fP"
|
||||
Clean the cache and re-calculate the cache file count and
|
||||
size totals\&. Normally the -c option should not be necessary as ccache
|
||||
keeps the cache below the specified limits at runtime and keeps
|
||||
@@ -66,16 +66,16 @@
|
||||
if you manually modify the cache contents or believe that the cache
|
||||
size statistics may be inaccurate\&.
|
||||
.IP
|
||||
-.IP "\fB-C\fP"
|
||||
+.IP "\fB-C, --clear\fP"
|
||||
Clear the entire cache, removing all cached files\&.
|
||||
.IP
|
||||
-.IP "\fB-F maxfiles\fP"
|
||||
+.IP "\fB-F <maxfiles>, --max-files=<maxfiles>\fP"
|
||||
This sets the maximum number of files allowed in
|
||||
the cache\&. The value is stored inside the cache directory and applies
|
||||
to all future compiles\&. Due to the way the value is stored the actual
|
||||
value used is always rounded down to the nearest multiple of 16\&.
|
||||
.IP
|
||||
-.IP "\fB-M maxsize\fP"
|
||||
+.IP "\fB-M <maxsize>, --max-size=<maxsize>\fP"
|
||||
This sets the maximum cache size\&. You can specify
|
||||
a value in gigabytes, megabytes or kilobytes by appending a G, M or K
|
||||
to the value\&. The default is gigabytes\&. The actual value stored is
|
|
@ -0,0 +1,13 @@
|
|||
diff -ru ccache-2.4/ccache.c ccache-2.4-tp/ccache.c
|
||||
--- ccache.c 2007-05-20 03:14:19.000000000 +1000
|
||||
+++ ccache.c 2007-05-20 03:17:54.000000000 +1000
|
||||
@@ -641,6 +641,9 @@
|
||||
|
||||
/* these are too hard */
|
||||
if (strcmp(argv[i], "-fbranch-probabilities")==0 ||
|
||||
+ strcmp(argv[i], "-fprofile-arcs") == 0 ||
|
||||
+ strcmp(argv[i], "-ftest-coverage") == 0 ||
|
||||
+ strcmp(argv[i], "--coverage") == 0 ||
|
||||
strcmp(argv[i], "-M") == 0 ||
|
||||
strcmp(argv[i], "-MM") == 0 ||
|
||||
strcmp(argv[i], "-x") == 0) {
|
|
@ -0,0 +1,45 @@
|
|||
--- ccache.1.orig 2007-05-20 17:30:57.000000000 +1200
|
||||
+++ ccache.1 2007-05-20 17:31:27.000000000 +1200
|
||||
@@ -367,12 +367,6 @@
|
||||
.IP o
|
||||
ccache avoids a double call to cpp on a cache miss
|
||||
.PP
|
||||
-.SH "BUGS"
|
||||
-.PP
|
||||
-When the cache is stored on an NFS filesystem, the filesystem must be
|
||||
-exported with the \fBno_subtree_check\fP option to make renames between
|
||||
-directories reliable\&.
|
||||
-.PP
|
||||
.SH "CREDITS"
|
||||
.PP
|
||||
Thanks to the following people for their contributions to ccache
|
||||
--- util.c.patched 2007-05-20 18:19:11.000000000 +1200
|
||||
+++ util.c 2007-05-20 18:20:55.000000000 +1200
|
||||
@@ -58,9 +58,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
+static int safe_rename(const char* oldpath, const char* newpath)
|
||||
+{
|
||||
+ /* safe_rename is for creating entries in the cache.
|
||||
+
|
||||
+ Works like rename(), but it never overwrites an existing
|
||||
+ cache entry. This avoids corruption on NFS. */
|
||||
+ int status = link( oldpath, newpath );
|
||||
+ if( status == 0 || errno == EEXIST )
|
||||
+ {
|
||||
+ return unlink( oldpath );
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ return -1;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/* move a file using rename */
|
||||
int move_file(const char *src, const char *dest) {
|
||||
- return rename(src, dest);
|
||||
+ return safe_rename(src, dest);
|
||||
}
|
||||
|
||||
/* copy a file - used when hard links don't work
|
|
@ -0,0 +1,77 @@
|
|||
--- ccache.c Mon Sep 13 11:38:30 2004
|
||||
+++ ccache.c Thu Jun 21 22:17:32 2007
|
||||
@@ -627,6 +627,13 @@ static void process_args(int argc, char
|
||||
int found_S_opt = 0;
|
||||
struct stat st;
|
||||
char *e;
|
||||
+ /* is gcc being asked to output dependencies? */
|
||||
+ int generating_dependencies = 0;
|
||||
+ /* is the dependency makefile name overridden with -MF? */
|
||||
+ int dependency_filename_specified = 0;
|
||||
+ /* is the dependency makefile target name specified with -MQ or -MF? */
|
||||
+ int dependency_target_specified = 0;
|
||||
+
|
||||
|
||||
stripped_args = args_init(0, NULL);
|
||||
|
||||
@@ -702,6 +709,18 @@ static void process_args(int argc, char
|
||||
continue;
|
||||
}
|
||||
|
||||
+ /* These options require special handling, because they
|
||||
+ behave differently with gcc -E, when the output
|
||||
+ file is not specified. */
|
||||
+
|
||||
+ if (strcmp(argv[i], "-MD") == 0 || strcmp(argv[i], "-MMD") == 0) {
|
||||
+ generating_dependencies = 1;
|
||||
+ } else if (strcmp(argv[i], "-MF") == 0) {
|
||||
+ dependency_filename_specified = 1;
|
||||
+ } else if (strcmp(argv[i], "-MQ") == 0 || strcmp(argv[i], "-MT") == 0) {
|
||||
+ dependency_target_specified = 1;
|
||||
+ }
|
||||
+
|
||||
/* options that take an argument */
|
||||
{
|
||||
const char *opts[] = {"-I", "-include", "-imacros", "-iprefix",
|
||||
@@ -812,6 +831,41 @@ static void process_args(int argc, char
|
||||
}
|
||||
p[1] = found_S_opt ? 's' : 'o';
|
||||
p[2] = 0;
|
||||
+ }
|
||||
+
|
||||
+ /* If dependencies are generated, configure the preprocessor */
|
||||
+
|
||||
+ if (generating_dependencies && output_file) {
|
||||
+ if (!dependency_filename_specified) {
|
||||
+ char *default_depfile_name = x_strdup(output_file);
|
||||
+ char *p = strrchr(default_depfile_name, '.');
|
||||
+
|
||||
+ if (p) {
|
||||
+ if (strlen(p) < 2) {
|
||||
+ stats_update(STATS_ARGS);
|
||||
+ failed();
|
||||
+ return;
|
||||
+ }
|
||||
+ *p = 0;
|
||||
+ }
|
||||
+ else {
|
||||
+ int len = p - default_depfile_name;
|
||||
+
|
||||
+ p = x_malloc(len + 3);
|
||||
+ strncpy(default_depfile_name, p, len - 1);
|
||||
+ free(default_depfile_name);
|
||||
+ default_depfile_name = p;
|
||||
+ }
|
||||
+
|
||||
+ strcat(default_depfile_name, ".d");
|
||||
+ args_add(stripped_args, "-MF");
|
||||
+ args_add(stripped_args, default_depfile_name);
|
||||
+ }
|
||||
+
|
||||
+ if (!dependency_target_specified) {
|
||||
+ args_add(stripped_args, "-MT");
|
||||
+ args_add(stripped_args, output_file);
|
||||
+ }
|
||||
}
|
||||
|
||||
/* cope with -o /dev/null */
|
|
@ -0,0 +1,75 @@
|
|||
Index: ccache.c
|
||||
===================================================================
|
||||
--- ccache.c (révision 7695)
|
||||
+++ ccache.c (copie de travail)
|
||||
@@ -1029,6 +1029,14 @@
|
||||
exit(1);
|
||||
}
|
||||
|
||||
+ if (!getenv("CCACHE_READONLY")) {
|
||||
+ if (create_cachedirtag(cache_dir) != 0) {
|
||||
+ fprintf(stderr,"ccache: failed to create %s/CACHEDIR.TAG (%s)\n",
|
||||
+ cache_dir, strerror(errno));
|
||||
+ exit(1);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
ccache(argc, argv);
|
||||
return 1;
|
||||
}
|
||||
Index: ccache.h
|
||||
===================================================================
|
||||
--- ccache.h (révision 7695)
|
||||
+++ ccache.h (copie de travail)
|
||||
@@ -81,6 +81,7 @@
|
||||
int copy_file(const char *src, const char *dest);
|
||||
|
||||
int create_dir(const char *dir);
|
||||
+int create_cachedirtag(const char *dir);
|
||||
void x_asprintf(char **ptr, const char *format, ...);
|
||||
char *x_strdup(const char *s);
|
||||
void *x_realloc(void *ptr, size_t size);
|
||||
Index: util.c
|
||||
===================================================================
|
||||
--- util.c (révision 7695)
|
||||
+++ util.c (copie de travail)
|
||||
@@ -138,6 +138,39 @@
|
||||
return 0;
|
||||
}
|
||||
|
||||
+char const CACHEDIR_TAG[] =
|
||||
+ "Signature: 8a477f597d28d172789f06886806bc55\n"
|
||||
+ "# This file is a cache directory tag created by ccache.\n"
|
||||
+ "# For information about cache directory tags, see:\n"
|
||||
+ "# http://www.brynosaurus.com/cachedir/\n";
|
||||
+
|
||||
+int create_cachedirtag(const char *dir)
|
||||
+{
|
||||
+ char *filename;
|
||||
+ struct stat st;
|
||||
+ FILE *f;
|
||||
+ x_asprintf(&filename, "%s/CACHEDIR.TAG", dir);
|
||||
+ if (stat(filename, &st) == 0) {
|
||||
+ if (S_ISREG(st.st_mode)) {
|
||||
+ goto success;
|
||||
+ }
|
||||
+ errno = EEXIST;
|
||||
+ goto error;
|
||||
+ }
|
||||
+ f = fopen(filename, "w");
|
||||
+ if (!f) goto error;
|
||||
+ if (fwrite(CACHEDIR_TAG, sizeof(CACHEDIR_TAG)-1, 1, f) != 1) {
|
||||
+ goto error;
|
||||
+ }
|
||||
+ if (fclose(f)) goto error;
|
||||
+success:
|
||||
+ free(filename);
|
||||
+ return 0;
|
||||
+error:
|
||||
+ free(filename);
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
this is like asprintf() but dies if the malloc fails
|
||||
note that we use vsnprintf in a rather poor way to make this more portable
|
|
@ -0,0 +1,89 @@
|
|||
Index: ccache.1
|
||||
===================================================================
|
||||
--- ccache.1 (révision 7695)
|
||||
+++ ccache.1 (copie de travail)
|
||||
@@ -49,7 +49,7 @@
|
||||
.IP "\fB-s\fP"
|
||||
Print the current statistics summary for the cache\&. The
|
||||
statistics are stored spread across the subdirectories of the
|
||||
-cache\&. Using "ccache -s" adds up the statistics across all
|
||||
+cache\&. Using "ccache \-s" adds up the statistics across all
|
||||
subdirectories and prints the totals\&.
|
||||
.IP
|
||||
.IP "\fB-z\fP"
|
||||
@@ -60,7 +60,7 @@
|
||||
.IP
|
||||
.IP "\fB-c\fP"
|
||||
Clean the cache and re-calculate the cache file count and
|
||||
-size totals\&. Normally the -c option should not be necessary as ccache
|
||||
+size totals\&. Normally the \-c option should not be necessary as ccache
|
||||
keeps the cache below the specified limits at runtime and keeps
|
||||
statistics up to date on each compile\&. This option is mostly useful
|
||||
if you manually modify the cache contents or believe that the cache
|
||||
@@ -100,9 +100,9 @@
|
||||
|
||||
|
||||
cp ccache /usr/local/bin/
|
||||
- ln -s /usr/local/bin/ccache /usr/local/bin/gcc
|
||||
- ln -s /usr/local/bin/ccache /usr/local/bin/g++
|
||||
- ln -s /usr/local/bin/ccache /usr/local/bin/cc
|
||||
+ ln \-s /usr/local/bin/ccache /usr/local/bin/gcc
|
||||
+ ln \-s /usr/local/bin/ccache /usr/local/bin/g++
|
||||
+ ln \-s /usr/local/bin/ccache /usr/local/bin/cc
|
||||
|
||||
.fi
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
.PP
|
||||
When run as a compiler front end ccache usually just takes the same
|
||||
command line options as the compiler you are using\&. The only exception
|
||||
-to this is the option \&'--ccache-skip\&'\&. That option can be used to tell
|
||||
+to this is the option \&'\-\-ccache-skip\&'\&. That option can be used to tell
|
||||
ccache that the next option is definitely not a input filename, and
|
||||
should be passed along to the compiler as-is\&.
|
||||
.PP
|
||||
@@ -128,7 +128,7 @@
|
||||
of the resulting object file (among other things)\&. The heuristic
|
||||
ccache uses in this parse is that any string on the command line that
|
||||
exists as a file is treated as an input file name (usually a C
|
||||
-file)\&. By using --ccache-skip you can force an option to not be
|
||||
+file)\&. By using \-\-ccache-skip you can force an option to not be
|
||||
treated as an input file name and instead be passed along to the
|
||||
compiler as a command line option\&.
|
||||
.PP
|
||||
@@ -238,7 +238,7 @@
|
||||
.IP "\fBCCACHE_UNIFY\fP"
|
||||
If you set the environment variable CCACHE_UNIFY
|
||||
then ccache will use the C/C++ unifier when hashing the pre-processor
|
||||
-output if -g is not used in the compile\&. The unifier is slower than a
|
||||
+output if \-g is not used in the compile\&. The unifier is slower than a
|
||||
normal hash, so setting this environment variable loses a little bit
|
||||
of speed, but it means that ccache can take advantage of not
|
||||
recompiling when the changes to the source code consist of
|
||||
@@ -262,7 +262,7 @@
|
||||
.PP
|
||||
By default ccache has a one gigabyte limit on the cache size and no
|
||||
maximum number of files\&. You can set a different limit using the
|
||||
-"ccache -M" and "ccache -F" options, which set the size and number of
|
||||
+"ccache \-M" and "ccache \-F" options, which set the size and number of
|
||||
files limits\&.
|
||||
.PP
|
||||
When these limits are reached ccache will reduce the cache to 20%
|
||||
@@ -276,7 +276,7 @@
|
||||
that it is the same code by forming a hash of:
|
||||
.PP
|
||||
.IP o
|
||||
-the pre-processor output from running the compiler with -E
|
||||
+the pre-processor output from running the compiler with \-E
|
||||
.IP o
|
||||
the command line options
|
||||
.IP o
|
||||
@@ -331,7 +331,7 @@
|
||||
.IP o
|
||||
Make sure that the setgid bit is set on all directories in the
|
||||
cache\&. This tells the filesystem to inherit group ownership for new
|
||||
-directories\&. The command "chmod g+s `find $CCACHE_DIR -type d`" might
|
||||
+directories\&. The command "chmod g+s `find $CCACHE_DIR \-type d`" might
|
||||
be useful for this\&.
|
||||
.PP
|
||||
.SH "HISTORY"
|
|
@ -0,0 +1,11 @@
|
|||
--- Makefile.in.orig 2008-03-23 17:01:19.000000000 +1300
|
||||
+++ Makefile.in 2008-03-23 17:03:03.000000000 +1300
|
||||
@@ -21,7 +21,7 @@
|
||||
docs: ccache.1 web/ccache-man.html
|
||||
|
||||
ccache$(EXEEXT): $(OBJS) $(HEADERS)
|
||||
- $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||
|
||||
ccache.1: ccache.yo
|
||||
-yodl2man -o ccache.1 ccache.yo
|
|
@ -0,0 +1,23 @@
|
|||
--- ccache.c (révision 8804)
|
||||
+++ ccache.c (copie de travail)
|
||||
@@ -481,6 +481,9 @@
|
||||
return;
|
||||
}
|
||||
|
||||
+ /* update timestamps for LRU cleanup
|
||||
+ also gives output_file a sensible mtime when hard-linking (for make) */
|
||||
+ utime(hashname, NULL);
|
||||
utime(stderr_file, NULL);
|
||||
|
||||
if (strcmp(output_file, "/dev/null") == 0) {
|
||||
@@ -513,10 +516,6 @@
|
||||
failed();
|
||||
}
|
||||
}
|
||||
- if (ret == 0) {
|
||||
- /* update the mtime on the file so that make doesn't get confused */
|
||||
- utime(output_file, NULL);
|
||||
- }
|
||||
|
||||
/* get rid of the intermediate preprocessor file */
|
||||
if (i_tmpfile) {
|
|
@ -0,0 +1,85 @@
|
|||
--- ccache.c 2004-09-13 03:38:30.000000000 -0700
|
||||
+++ ccache.c 2006-06-09 16:29:16.695117780 -0700
|
||||
@@ -481,8 +481,13 @@
|
||||
|
||||
/* update timestamps for LRU cleanup
|
||||
also gives output_file a sensible mtime when hard-linking (for make) */
|
||||
+#ifdef HAVE_UTIMES
|
||||
+ utimes(hashname, NULL);
|
||||
+ utimes(stderr_file, NULL);
|
||||
+#else
|
||||
utime(hashname, NULL);
|
||||
utime(stderr_file, NULL);
|
||||
+#endif
|
||||
|
||||
if (strcmp(output_file, "/dev/null") == 0) {
|
||||
ret = 0;
|
||||
--- ccache.h 2004-09-13 03:38:30.000000000 -0700
|
||||
+++ ccache.h 2006-06-09 16:28:16.601658626 -0700
|
||||
@@ -22,6 +22,9 @@
|
||||
#ifdef HAVE_PWD_H
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
+#ifdef HAVE_SYS_TIME_H
|
||||
+#include <sys/time.h>
|
||||
+#endif
|
||||
|
||||
#define STATUS_NOTFOUND 3
|
||||
#define STATUS_FATAL 4
|
||||
--- config.h.in 2003-09-27 21:48:17.000000000 -0700
|
||||
+++ config.h.in 2006-06-09 16:25:43.000000000 -0700
|
||||
@@ -19,6 +19,9 @@
|
||||
/* Define to 1 if you have the `gethostname' function. */
|
||||
#undef HAVE_GETHOSTNAME
|
||||
|
||||
+/* Define to 1 if you have the `getpwuid' function. */
|
||||
+#undef HAVE_GETPWUID
|
||||
+
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
@@ -31,6 +34,9 @@
|
||||
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
|
||||
#undef HAVE_NDIR_H
|
||||
|
||||
+/* Define to 1 if you have the <pwd.h> header file. */
|
||||
+#undef HAVE_PWD_H
|
||||
+
|
||||
/* Define to 1 if you have the `realpath' function. */
|
||||
#undef HAVE_REALPATH
|
||||
|
||||
@@ -60,6 +66,9 @@
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
+/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
+#undef HAVE_SYS_TIME_H
|
||||
+
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
@@ -69,6 +78,9 @@
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
+/* Define to 1 if you have the `utimes' function. */
|
||||
+#undef HAVE_UTIMES
|
||||
+
|
||||
/* Define to 1 if you have the `vasprintf' function. */
|
||||
#undef HAVE_VASPRINTF
|
||||
|
||||
--- configure.in 2004-09-13 03:38:30.000000000 -0700
|
||||
+++ configure.in 2006-06-09 16:25:15.541288184 -0700
|
||||
@@ -27,10 +27,11 @@
|
||||
AC_HEADER_TIME
|
||||
AC_HEADER_SYS_WAIT
|
||||
|
||||
-AC_CHECK_HEADERS(ctype.h strings.h stdlib.h string.h pwd.h)
|
||||
+AC_CHECK_HEADERS(ctype.h strings.h stdlib.h string.h pwd.h sys/time.h)
|
||||
|
||||
AC_CHECK_FUNCS(realpath snprintf vsnprintf vasprintf asprintf mkstemp)
|
||||
AC_CHECK_FUNCS(gethostname getpwuid)
|
||||
+AC_CHECK_FUNCS(utimes)
|
||||
|
||||
AC_CACHE_CHECK([for compar_fn_t in stdlib.h],ccache_cv_COMPAR_FN_T, [
|
||||
AC_TRY_COMPILE(
|
|
@ -0,0 +1,83 @@
|
|||
--- stats.c (révision 8804)
|
||||
+++ stats.c (copie de travail)
|
||||
@@ -286,7 +286,7 @@
|
||||
|
||||
|
||||
/* set the per directory limits */
|
||||
-void stats_set_limits(long maxfiles, long maxsize)
|
||||
+int stats_set_limits(long maxfiles, long maxsize)
|
||||
{
|
||||
int dir;
|
||||
unsigned counters[STATS_END];
|
||||
@@ -298,7 +298,9 @@
|
||||
maxsize /= 16;
|
||||
}
|
||||
|
||||
- create_dir(cache_dir);
|
||||
+ if (create_dir(cache_dir) != 0) {
|
||||
+ return 1;
|
||||
+ }
|
||||
|
||||
/* set the limits in each directory */
|
||||
for (dir=0;dir<=0xF;dir++) {
|
||||
@@ -306,7 +308,9 @@
|
||||
int fd;
|
||||
|
||||
x_asprintf(&cdir, "%s/%1x", cache_dir, dir);
|
||||
- create_dir(cdir);
|
||||
+ if (create_dir(cdir) != 0) {
|
||||
+ return 1;
|
||||
+ }
|
||||
x_asprintf(&fname, "%s/stats", cdir);
|
||||
free(cdir);
|
||||
|
||||
@@ -326,6 +330,8 @@
|
||||
}
|
||||
free(fname);
|
||||
}
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
/* set the per directory sizes */
|
||||
--- ccache.c (révision 8804)
|
||||
+++ ccache.c (copie de travail)
|
||||
@@ -935,15 +934,23 @@
|
||||
case 'F':
|
||||
check_cache_dir();
|
||||
v = atoi(optarg);
|
||||
- stats_set_limits(v, -1);
|
||||
- printf("Set cache file limit to %u\n", (unsigned)v);
|
||||
+ if (stats_set_limits(v, -1) == 0) {
|
||||
+ printf("Set cache file limit to %u\n", (unsigned)v);
|
||||
+ } else {
|
||||
+ printf("Could not set cache file limit.\n");
|
||||
+ exit(1);
|
||||
+ }
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
check_cache_dir();
|
||||
v = value_units(optarg);
|
||||
- stats_set_limits(-1, v);
|
||||
- printf("Set cache size limit to %uk\n", (unsigned)v);
|
||||
+ if (stats_set_limits(-1, v) == 0) {
|
||||
+ printf("Set cache size limit to %uk\n", (unsigned)v);
|
||||
+ } else {
|
||||
+ printf("Could not set cache size limit.\n");
|
||||
+ exit(1);
|
||||
+ }
|
||||
break;
|
||||
|
||||
default:
|
||||
--- ccache.h (révision 8804)
|
||||
+++ ccache.h (copie de travail)
|
||||
@@ -101,7 +101,7 @@
|
||||
void stats_summary(void);
|
||||
void stats_tocache(size_t size);
|
||||
void stats_read(const char *stats_file, unsigned counters[STATS_END]);
|
||||
-void stats_set_limits(long maxfiles, long maxsize);
|
||||
+int stats_set_limits(long maxfiles, long maxsize);
|
||||
size_t value_units(const char *s);
|
||||
void display_size(unsigned v);
|
||||
void stats_set_sizes(const char *dir, size_t num_files, size_t total_size);
|
|
@ -0,0 +1,33 @@
|
|||
--- web/index.html~ 2004-09-13 13:38:30.000000000 +0300
|
||||
+++ web/index.html 2004-09-26 01:04:38.458008118 +0300
|
||||
@@ -29,10 +29,10 @@
|
||||
<li>fixed handling of HOME environment variable
|
||||
</ul>
|
||||
|
||||
-See the <a href="/ccache/ccache-man.html">manual page</a> for details
|
||||
+See the <a href="ccache-man.html">manual page</a> for details
|
||||
on the new options.<p>
|
||||
|
||||
-You can get this release from the <a href="/ftp/ccache/">download directory</a>
|
||||
+You can get this release from the <a href="http://ccache.samba.org/ftp/ccache/">download directory</a>
|
||||
|
||||
<p>NOTE! This release changes the hash input slighly, so you will
|
||||
probably find that you will not get any hits against your existing
|
||||
@@ -87,7 +87,7 @@
|
||||
|
||||
<h2>Documentation</h2>
|
||||
|
||||
-See the <a href="/ccache/ccache-man.html">manual page</a>
|
||||
+See the <a href="ccache-man.html">manual page</a>
|
||||
|
||||
|
||||
<h2>Performance</h2>
|
||||
@@ -116,7 +116,7 @@
|
||||
<h2>Download</h2>
|
||||
|
||||
You can download the latest release from the <a
|
||||
-href="/ftp/ccache/">download directory</a>.<p>
|
||||
+href="http://ccache.samba.org/ftp/ccache/">download directory</a>.<p>
|
||||
|
||||
For the bleeding edge, you can fetch ccache via CVS or
|
||||
rsync. To fetch via cvs use the following command:
|
|
@ -0,0 +1,48 @@
|
|||
Index: ccache.1
|
||||
===================================================================
|
||||
RCS file: /cvsroot/ccache/ccache.1,v
|
||||
retrieving revision 1.26
|
||||
diff -u -r1.26 ccache.1
|
||||
--- ccache.1 24 Nov 2005 21:10:08 -0000 1.26
|
||||
+++ ccache.1 21 Jul 2007 21:03:32 -0000
|
||||
@@ -330,7 +330,7 @@
|
||||
.IP o
|
||||
Use the same \fBCCACHE_DIR\fP environment variable setting
|
||||
.IP o
|
||||
-Set the \fBCCACHE_NOLINK\fP environment variable
|
||||
+Unset the \fBCCACHE_HARDLINK\fP environment variable
|
||||
.IP o
|
||||
Make sure everyone sets the CCACHE_UMASK environment variable
|
||||
to 002, this ensures that cached files are accessible to everyone in
|
||||
Index: ccache.yo
|
||||
===================================================================
|
||||
RCS file: /cvsroot/ccache/ccache.yo,v
|
||||
retrieving revision 1.27
|
||||
diff -u -r1.27 ccache.yo
|
||||
--- ccache.yo 24 Nov 2005 21:54:09 -0000 1.27
|
||||
+++ ccache.yo 21 Jul 2007 21:03:32 -0000
|
||||
@@ -289,7 +289,7 @@
|
||||
|
||||
itemize(
|
||||
it() Use the same bf(CCACHE_DIR) environment variable setting
|
||||
- it() Set the bf(CCACHE_NOLINK) environment variable
|
||||
+ it() Unset the bf(CCACHE_HARDLINK) environment variable
|
||||
it() Make sure everyone sets the CCACHE_UMASK environment variable
|
||||
to 002, this ensures that cached files are accessible to everyone in
|
||||
the group.
|
||||
Index: web/ccache-man.html
|
||||
===================================================================
|
||||
RCS file: /cvsroot/ccache/web/ccache-man.html,v
|
||||
retrieving revision 1.25
|
||||
diff -u -r1.25 ccache-man.html
|
||||
--- web/ccache-man.html 13 Sep 2004 10:38:17 -0000 1.25
|
||||
+++ web/ccache-man.html 21 Jul 2007 21:03:32 -0000
|
||||
@@ -256,7 +256,7 @@
|
||||
following conditions need to be met:
|
||||
<p><ul>
|
||||
<li > Use the same <strong>CCACHE_DIR</strong> environment variable setting
|
||||
- <li > Set the <strong>CCACHE_NOLINK</strong> environment variable
|
||||
+ <li > Unset the <strong>CCACHE_HARDLINK</strong> environment variable
|
||||
<li > Make sure everyone sets the CCACHE_UMASK environment variable
|
||||
to 002, this ensures that cached files are accessible to everyone in
|
||||
the group.
|
|
@ -0,0 +1,47 @@
|
|||
01_no_home.diff:
|
||||
Francois Marier <francois@debian.org>
|
||||
Made especially for the Debian package.
|
||||
|
||||
02_ccache_compressed.diff:
|
||||
Lars Gustäbel <lars@gustaebel.de>
|
||||
http://www.gustaebel.de/lars/ccache/ (downloaded on 2007-05-20)
|
||||
|
||||
03_long_options.diff:
|
||||
Francois Marier <francois@debian.org>
|
||||
Made especially for the Debian package.
|
||||
|
||||
04_ignore_profile.diff:
|
||||
Ted Percival <ted@midg3t.net>
|
||||
http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=20;filename=ccache-profile.patch;att=1;bug=215849
|
||||
|
||||
05_nfs_fix.diff:
|
||||
John Coiner <john.coiner@amd.com>
|
||||
http://lists.samba.org/archive/ccache/2007q1/000265.html
|
||||
|
||||
06_md.diff:
|
||||
Andrea Bittau <a.bittau@cs.ucl.ac.uk>
|
||||
http://darkircop.org/ccache/ccache-2.4-md.patch (downloaded on 2007-06-30)
|
||||
|
||||
07_cachedirtag.diff:
|
||||
Karl Chen <quarl@cs.berkeley.edu>
|
||||
http://lists.samba.org/archive/ccache/2008q1/000316.html (downloaded on 2008-02-02)
|
||||
|
||||
08_manpage_hyphens.diff:
|
||||
Francois Marier <francois@debian.org>
|
||||
Made especially for the Debian package.
|
||||
|
||||
09_respect_ldflags.diff:
|
||||
Lisa Seelye <lisa@gentoo.org>
|
||||
http://sources.gentoo.org/viewcvs.py/gentoo-x86/dev-util/ccache/files/ccache-2.4-respectflags.patch?rev=1.1&view=markup
|
||||
|
||||
10_lru_cleanup.diff:
|
||||
RW <fbsd06@mlists.homeunix.com>
|
||||
http://lists.samba.org/archive/ccache/2008q2/000339.html (downloaded on 2008-04-11)
|
||||
|
||||
11_utimes.diff:
|
||||
Robin H. Johnson <robbat2@gentoo.org>
|
||||
http://sources.gentoo.org/viewcvs.py/gentoo-x86/dev-util/ccache/files/ccache-2.4-utimes.patch?rev=1.1&view=markup
|
||||
|
||||
12_cachesize_permissions.diff:
|
||||
Francois Marier <francois@debian.org>
|
||||
Made especially for the Debian package to fix http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=332527
|
|
@ -0,0 +1,141 @@
|
|||
#!/usr/bin/make -f
|
||||
# Sample debian/rules that uses debhelper.
|
||||
# GNU copyright 1997 to 1999 by Joey Hess.
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
# These are used for cross-compiling and for saving the configure script
|
||||
# from having to guess our platform (since we know it already)
|
||||
export DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
|
||||
export DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
|
||||
|
||||
ifeq ($(DEB_BUILD_GNU_TYPE), $(DEB_HOST_GNU_TYPE))
|
||||
confflags += --build $(DEB_HOST_GNU_TYPE)
|
||||
else
|
||||
confflags += --build $(DEB_BUILD_GNU_TYPE) --host $(DEB_HOST_GNU_TYPE)
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
|
||||
CFLAGS += -g
|
||||
endif
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
INSTALL_PROGRAM += -s
|
||||
endif
|
||||
|
||||
config.status: configure
|
||||
dh_testdir
|
||||
|
||||
# Apply Debian specific patches
|
||||
cp $(CURDIR)/ccache.c $(CURDIR)/ccache.c.unpatched
|
||||
cp $(CURDIR)/util.c $(CURDIR)/util.c.unpatched
|
||||
cp $(CURDIR)/ccache.1 $(CURDIR)/ccache.1.unpatched
|
||||
cp $(CURDIR)/ccache.h $(CURDIR)/ccache.h.unpatched
|
||||
cp $(CURDIR)/ccache.yo $(CURDIR)/ccache.yo.unpatched
|
||||
cp $(CURDIR)/config.h.in $(CURDIR)/config.h.in.unpatched
|
||||
cp $(CURDIR)/configure $(CURDIR)/configure.unpatched
|
||||
cp $(CURDIR)/configure.in $(CURDIR)/configure.in.unpatched
|
||||
cp $(CURDIR)/Makefile.in $(CURDIR)/Makefile.in.unpatched
|
||||
if test ! -f patch-stamp; then \
|
||||
for patch in $(CURDIR)/debian/patches/*.diff ;\
|
||||
do \
|
||||
echo APPLYING PATCH\: $${patch##*/};\
|
||||
patch -p0 < $$patch ;\
|
||||
done ;\
|
||||
touch patch-stamp ;\
|
||||
fi
|
||||
chmod +x $(CURDIR)/manage-cache.sh
|
||||
|
||||
./configure $(confflags) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info
|
||||
|
||||
build: build-stamp
|
||||
|
||||
build-stamp: config.status
|
||||
dh_testdir
|
||||
|
||||
$(MAKE)
|
||||
|
||||
touch build-stamp
|
||||
|
||||
clean:
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
rm -f build-stamp
|
||||
|
||||
# Unapply patches
|
||||
-test -r $(CURDIR)/ccache.c.unpatched && mv $(CURDIR)/ccache.c.unpatched $(CURDIR)/ccache.c
|
||||
-test -r $(CURDIR)/util.c.unpatched && mv $(CURDIR)/util.c.unpatched $(CURDIR)/util.c
|
||||
-test -r $(CURDIR)/ccache.1.unpatched && mv $(CURDIR)/ccache.1.unpatched $(CURDIR)/ccache.1
|
||||
-test -r $(CURDIR)/ccache.h.unpatched && mv $(CURDIR)/ccache.h.unpatched $(CURDIR)/ccache.h
|
||||
-test -r $(CURDIR)/ccache.yo.unpatched && mv $(CURDIR)/ccache.yo.unpatched $(CURDIR)/ccache.yo
|
||||
-test -r $(CURDIR)/config.h.in.unpatched && mv $(CURDIR)/config.h.in.unpatched $(CURDIR)/config.h.in
|
||||
-test -r $(CURDIR)/configure.unpatched && mv $(CURDIR)/configure.unpatched $(CURDIR)/configure
|
||||
-test -r $(CURDIR)/configure.in.unpatched && mv $(CURDIR)/configure.in.unpatched $(CURDIR)/configure.in
|
||||
-test -r $(CURDIR)/Makefile.in.unpatched && mv $(CURDIR)/Makefile.in.unpatched $(CURDIR)/Makefile.in
|
||||
-rm -f $(CURDIR)/manage-cache.sh
|
||||
-rm -f patch-stamp
|
||||
|
||||
[ ! -f Makefile ] || $(MAKE) distclean
|
||||
|
||||
dh_clean
|
||||
|
||||
# Update config.sub and config.guess
|
||||
-test -r /usr/share/misc/config.sub && \
|
||||
cp -f /usr/share/misc/config.sub config.sub
|
||||
-test -r /usr/share/misc/config.guess && \
|
||||
cp -f /usr/share/misc/config.guess config.guess
|
||||
|
||||
|
||||
install: build
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_clean -k
|
||||
dh_installdirs
|
||||
|
||||
# Add here commands to install the package into debian/ccache.
|
||||
$(MAKE) install prefix=$(CURDIR)/debian/ccache/usr
|
||||
|
||||
ln -s ../../bin/ccache $(CURDIR)/debian/ccache/usr/lib/ccache/$(DEB_BUILD_GNU_TYPE)-gcc
|
||||
ln -s ../../bin/ccache $(CURDIR)/debian/ccache/usr/lib/ccache/$(DEB_BUILD_GNU_TYPE)-g++
|
||||
set -e; for ver in 2.95 3.0 3.2 3.3 3.4 4.0 4.1 4.2 4.3; do \
|
||||
ln -s ../../bin/ccache $(CURDIR)/debian/ccache/usr/lib/ccache/$(DEB_BUILD_GNU_TYPE)-gcc-$$ver; \
|
||||
ln -s ../../bin/ccache $(CURDIR)/debian/ccache/usr/lib/ccache/gcc-$$ver; \
|
||||
ln -s ../../bin/ccache $(CURDIR)/debian/ccache/usr/lib/ccache/$(DEB_BUILD_GNU_TYPE)-g++-$$ver; \
|
||||
ln -s ../../bin/ccache $(CURDIR)/debian/ccache/usr/lib/ccache/g++-$$ver; \
|
||||
done
|
||||
ln -s ../../bin/ccache $(CURDIR)/debian/ccache/usr/lib/ccache/cc
|
||||
ln -s ../../bin/ccache $(CURDIR)/debian/ccache/usr/lib/ccache/c++
|
||||
ln -s ../../bin/ccache $(CURDIR)/debian/ccache/usr/lib/ccache/gcc
|
||||
ln -s ../../bin/ccache $(CURDIR)/debian/ccache/usr/lib/ccache/g++
|
||||
ln -s ../../bin/ccache $(CURDIR)/debian/ccache/usr/lib/ccache/i586-mingw32msvc-c++
|
||||
ln -s ../../bin/ccache $(CURDIR)/debian/ccache/usr/lib/ccache/i586-mingw32msvc-cc
|
||||
ln -s ../../bin/ccache $(CURDIR)/debian/ccache/usr/lib/ccache/i586-mingw32msvc-g++
|
||||
ln -s ../../bin/ccache $(CURDIR)/debian/ccache/usr/lib/ccache/i586-mingw32msvc-gcc
|
||||
|
||||
# Build architecture-independent files here.
|
||||
binary-indep: build install
|
||||
# We have nothing to do by default.
|
||||
|
||||
# Build architecture-dependent files here.
|
||||
binary-arch: build install
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_installdocs
|
||||
dh_installexamples
|
||||
dh_installmenu
|
||||
dh_installcron
|
||||
dh_installman
|
||||
dh_installinfo
|
||||
dh_installchangelogs
|
||||
dh_link
|
||||
dh_strip
|
||||
dh_compress
|
||||
dh_fixperms
|
||||
dh_installdeb
|
||||
dh_shlibdeps
|
||||
dh_gencontrol
|
||||
dh_md5sums
|
||||
dh_builddeb
|
||||
|
||||
binary: binary-indep binary-arch
|
||||
.PHONY: build clean binary-indep binary-arch binary install
|
|
@ -0,0 +1,43 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Update compiler links to ccache (in /usr/local/bin)
|
||||
#
|
||||
# The idea is that /usr/local/bin is ahead of /usr/bin in your PATH, so adding
|
||||
# the link /usr/local/bin/cc -> /usr/bin/ccache means that it is run instead of
|
||||
# /usr/bin/cc
|
||||
#
|
||||
# Written by: Behan Webster <behanw@websterwood.com>
|
||||
#
|
||||
|
||||
DIRECTORY=/usr/local/bin
|
||||
CCACHE=/usr/bin/ccache
|
||||
CCDIR=/usr/lib/ccache
|
||||
|
||||
usage() {
|
||||
echo "Usage: `basename $0` [--directory <dir>] [--remove]"
|
||||
exit 0
|
||||
}
|
||||
|
||||
while [ $# -gt 0 ] ; do
|
||||
case "$1" in
|
||||
-d*|--d*|--directory) DIRECTORY=$2; shift; shift;;
|
||||
-h*|--h*|--help) usage;;
|
||||
-r*|--r*|--remove) REMOVE=1; shift;;
|
||||
-t*|--t*|--test) TEST=echo; shift;;
|
||||
esac
|
||||
done
|
||||
|
||||
for FILE in `cd $CCDIR; ls` ; do
|
||||
LINK=$DIRECTORY/$FILE
|
||||
if [ -z "$REMOVE" ] ; then
|
||||
# Add link
|
||||
$TEST ln -fs $CCACHE $LINK
|
||||
else
|
||||
# Remove link
|
||||
if [ -L "$LINK" ] ; then
|
||||
$TEST rm -f $LINK
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# vim: sw=4 ts=4
|
|
@ -0,0 +1,2 @@
|
|||
version=2
|
||||
http://samba.org/ftp/ccache/ccache-(.*)\.tar\.gz
|
|
@ -0,0 +1,287 @@
|
|||
/*
|
||||
Copyright (C) Andrew Tridgell 2002
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "ccache.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
char *argvtos(char **argv)
|
||||
{
|
||||
int i, len;
|
||||
char *ptr, *str;
|
||||
|
||||
for (i = 0, len = 0; argv[i]; i++) {
|
||||
len += strlen(argv[i]) + 3;
|
||||
}
|
||||
|
||||
str = ptr = (char *)malloc(len + 1);
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; argv[i]; i++) {
|
||||
len = strlen(argv[i]);
|
||||
*ptr++ = '"';
|
||||
memcpy(ptr, argv[i], len);
|
||||
ptr += len;
|
||||
*ptr++ = '"';
|
||||
*ptr++ = ' ';
|
||||
}
|
||||
*ptr = 0;
|
||||
|
||||
return str;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
execute a compiler backend, capturing all output to the given paths
|
||||
the full path to the compiler to run is in argv[0]
|
||||
*/
|
||||
int execute(char **argv,
|
||||
const char *path_stdout,
|
||||
const char *path_stderr)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
#if 1
|
||||
PROCESS_INFORMATION pinfo;
|
||||
STARTUPINFO sinfo;
|
||||
BOOL ret;
|
||||
DWORD exitcode;
|
||||
char *args;
|
||||
HANDLE fd_out, fd_err;
|
||||
SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
|
||||
|
||||
/* TODO: needs moving after possible exit() below, but before stdout is redirected */
|
||||
if (ccache_verbose) {
|
||||
display_execute_args(argv);
|
||||
}
|
||||
|
||||
fd_out = CreateFile(path_stdout, GENERIC_WRITE, 0, &sa, CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (fd_out == INVALID_HANDLE_VALUE) {
|
||||
return STATUS_NOCACHE;
|
||||
}
|
||||
|
||||
fd_err = CreateFile(path_stderr, GENERIC_WRITE, 0, &sa, CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (fd_err == INVALID_HANDLE_VALUE) {
|
||||
return STATUS_NOCACHE;
|
||||
}
|
||||
|
||||
ZeroMemory(&pinfo, sizeof(PROCESS_INFORMATION));
|
||||
ZeroMemory(&sinfo, sizeof(STARTUPINFO));
|
||||
|
||||
sinfo.cb = sizeof(STARTUPINFO);
|
||||
sinfo.hStdError = fd_err;
|
||||
sinfo.hStdOutput = fd_out;
|
||||
sinfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||
sinfo.dwFlags |= STARTF_USESTDHANDLES;
|
||||
|
||||
args = argvtos(argv);
|
||||
|
||||
ret = CreateProcessA(argv[0], args, NULL, NULL, TRUE, 0, NULL, NULL,
|
||||
&sinfo, &pinfo);
|
||||
|
||||
free(args);
|
||||
CloseHandle(fd_out);
|
||||
CloseHandle(fd_err);
|
||||
|
||||
if (ret == 0)
|
||||
return -1;
|
||||
|
||||
WaitForSingleObject(pinfo.hProcess, INFINITE);
|
||||
GetExitCodeProcess(pinfo.hProcess, &exitcode);
|
||||
CloseHandle(pinfo.hProcess);
|
||||
CloseHandle(pinfo.hThread);
|
||||
|
||||
return exitcode;
|
||||
#else /* possibly slightly faster */
|
||||
/* needs fixing to quote commandline options to handle spaces in CCACHE_DIR etc */
|
||||
int status = -2;
|
||||
int fd, std_od = -1, std_ed = -1;
|
||||
|
||||
/* TODO: needs moving after possible exit() below, but before stdout is redirected */
|
||||
if (ccache_verbose) {
|
||||
display_execute_args(argv);
|
||||
}
|
||||
|
||||
unlink(path_stdout);
|
||||
std_od = _dup(1);
|
||||
fd = _open(path_stdout, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666);
|
||||
if (fd == -1) {
|
||||
exit(STATUS_NOCACHE);
|
||||
}
|
||||
_dup2(fd, 1);
|
||||
_close(fd);
|
||||
|
||||
unlink(path_stderr);
|
||||
fd = _open(path_stderr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666);
|
||||
std_ed = _dup(2);
|
||||
if (fd == -1) {
|
||||
exit(STATUS_NOCACHE);
|
||||
}
|
||||
_dup2(fd, 2);
|
||||
_close(fd);
|
||||
|
||||
/* Spawn process (_exec* familly doesn't return) */
|
||||
status = _spawnv(_P_WAIT, argv[0], (const char **)argv);
|
||||
|
||||
/* Restore descriptors */
|
||||
if (std_od != -1) _dup2(std_od, 1);
|
||||
if (std_ed != -1) _dup2(std_ed, 2);
|
||||
_flushall();
|
||||
|
||||
return (status>0);
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
pid_t pid;
|
||||
int status;
|
||||
|
||||
pid = fork();
|
||||
if (pid == -1) fatal("Failed to fork");
|
||||
|
||||
if (pid == 0) {
|
||||
int fd;
|
||||
|
||||
/* TODO: needs moving after possible exit() below, but before stdout is redirected */
|
||||
if (ccache_verbose) {
|
||||
display_execute_args(argv);
|
||||
}
|
||||
|
||||
unlink(path_stdout);
|
||||
fd = open(path_stdout, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666);
|
||||
if (fd == -1) {
|
||||
exit(STATUS_NOCACHE);
|
||||
}
|
||||
dup2(fd, 1);
|
||||
close(fd);
|
||||
|
||||
unlink(path_stderr);
|
||||
fd = open(path_stderr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666);
|
||||
if (fd == -1) {
|
||||
exit(STATUS_NOCACHE);
|
||||
}
|
||||
dup2(fd, 2);
|
||||
close(fd);
|
||||
|
||||
exit(execv(argv[0], argv));
|
||||
}
|
||||
|
||||
if (waitpid(pid, &status, 0) != pid) {
|
||||
fatal("waitpid failed");
|
||||
}
|
||||
|
||||
if (WEXITSTATUS(status) == 0 && WIFSIGNALED(status)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return WEXITSTATUS(status);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
find an executable by name in $PATH. Exclude any that are links to exclude_name
|
||||
*/
|
||||
char *find_executable(const char *name, const char *exclude_name)
|
||||
{
|
||||
#if _WIN32
|
||||
(void)exclude_name;
|
||||
DWORD ret;
|
||||
char namebuf[MAX_PATH];
|
||||
|
||||
ret = SearchPathA(getenv("CCACHE_PATH"), name, ".exe",
|
||||
sizeof(namebuf), namebuf, NULL);
|
||||
if (ret != 0) {
|
||||
return x_strdup(namebuf);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
#else
|
||||
char *path;
|
||||
char *tok;
|
||||
struct stat st1, st2;
|
||||
|
||||
if (*name == '/') {
|
||||
return x_strdup(name);
|
||||
}
|
||||
|
||||
path = getenv("CCACHE_PATH");
|
||||
if (!path) {
|
||||
path = getenv("PATH");
|
||||
}
|
||||
if (!path) {
|
||||
cc_log("no PATH variable!?\n");
|
||||
stats_update(STATS_ENVIRONMMENT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
path = x_strdup(path);
|
||||
|
||||
/* search the path looking for the first compiler of the right name
|
||||
that isn't us */
|
||||
for (tok=strtok(path,":"); tok; tok = strtok(NULL, ":")) {
|
||||
char *fname;
|
||||
x_asprintf(&fname, "%s/%s", tok, name);
|
||||
/* look for a normal executable file */
|
||||
if (access(fname, X_OK) == 0 &&
|
||||
lstat(fname, &st1) == 0 &&
|
||||
stat(fname, &st2) == 0 &&
|
||||
S_ISREG(st2.st_mode)) {
|
||||
/* if its a symlink then ensure it doesn't
|
||||
point at something called exclude_name */
|
||||
if (S_ISLNK(st1.st_mode)) {
|
||||
char *buf = x_realpath(fname);
|
||||
if (buf) {
|
||||
char *p = str_basename(buf);
|
||||
if (strcmp(p, exclude_name) == 0) {
|
||||
/* its a link to "ccache" ! */
|
||||
free(p);
|
||||
free(buf);
|
||||
continue;
|
||||
}
|
||||
free(buf);
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
/* found it! */
|
||||
free(path);
|
||||
return fname;
|
||||
}
|
||||
free(fname);
|
||||
}
|
||||
free(path);
|
||||
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void display_execute_args(char **argv)
|
||||
{
|
||||
if (argv) {
|
||||
printf("ccache executing: ");
|
||||
while (*argv) {
|
||||
printf("%s ", *argv);
|
||||
++argv;
|
||||
}
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
Copyright (C) Andrew Tridgell 2002
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/*
|
||||
simple front-end functions to mdfour code
|
||||
*/
|
||||
|
||||
#include "ccache.h"
|
||||
|
||||
static struct mdfour md;
|
||||
|
||||
void hash_buffer(const char *s, int len)
|
||||
{
|
||||
mdfour_update(&md, (unsigned char *)s, len);
|
||||
}
|
||||
|
||||
void hash_start(void)
|
||||
{
|
||||
mdfour_begin(&md);
|
||||
}
|
||||
|
||||
void hash_string(const char *s)
|
||||
{
|
||||
hash_buffer(s, strlen(s));
|
||||
}
|
||||
|
||||
void hash_int(int x)
|
||||
{
|
||||
hash_buffer((char *)&x, sizeof(x));
|
||||
}
|
||||
|
||||
/* add contents of a file to the hash */
|
||||
void hash_file(const char *fname)
|
||||
{
|
||||
char buf[1024];
|
||||
int fd, n;
|
||||
|
||||
fd = open(fname, O_RDONLY|O_BINARY);
|
||||
if (fd == -1) {
|
||||
cc_log("Failed to open %s\n", fname);
|
||||
fatal("hash_file");
|
||||
}
|
||||
|
||||
while ((n = read(fd, buf, sizeof(buf))) > 0) {
|
||||
hash_buffer(buf, n);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* return the hash result as a static string */
|
||||
char *hash_result(void)
|
||||
{
|
||||
unsigned char sum[16];
|
||||
static char ret[53];
|
||||
int i;
|
||||
|
||||
hash_buffer(NULL, 0);
|
||||
mdfour_result(&md, sum);
|
||||
|
||||
for (i=0;i<16;i++) {
|
||||
sprintf(&ret[i*2], "%02x", (unsigned)sum[i]);
|
||||
}
|
||||
sprintf(&ret[i*2], "-%u", (unsigned)md.totalN);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,238 @@
|
|||
#! /bin/sh
|
||||
#
|
||||
# install - install a program, script, or datafile
|
||||
# This comes from X11R5.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
#
|
||||
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit="${DOITPROG-}"
|
||||
|
||||
|
||||
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||
|
||||
mvprog="${MVPROG-mv}"
|
||||
cpprog="${CPPROG-cp}"
|
||||
chmodprog="${CHMODPROG-chmod}"
|
||||
chownprog="${CHOWNPROG-chown}"
|
||||
chgrpprog="${CHGRPPROG-chgrp}"
|
||||
stripprog="${STRIPPROG-strip}"
|
||||
rmprog="${RMPROG-rm}"
|
||||
mkdirprog="${MKDIRPROG-mkdir}"
|
||||
|
||||
transformbasename=""
|
||||
transform_arg=""
|
||||
instcmd="$mvprog"
|
||||
chmodcmd="$chmodprog 0755"
|
||||
chowncmd=""
|
||||
chgrpcmd=""
|
||||
stripcmd=""
|
||||
rmcmd="$rmprog -f"
|
||||
mvcmd="$mvprog"
|
||||
src=""
|
||||
dst=""
|
||||
dir_arg=""
|
||||
|
||||
while [ x"$1" != x ]; do
|
||||
case $1 in
|
||||
-c) instcmd="$cpprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-d) dir_arg=true
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-m) chmodcmd="$chmodprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-s) stripcmd="$stripprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
*) if [ x"$src" = x ]
|
||||
then
|
||||
src=$1
|
||||
else
|
||||
# this colon is to work around a 386BSD /bin/sh bug
|
||||
:
|
||||
dst=$1
|
||||
fi
|
||||
shift
|
||||
continue;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ x"$src" = x ]
|
||||
then
|
||||
echo "install: no input file specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]; then
|
||||
dst=$src
|
||||
src=""
|
||||
|
||||
if [ -d $dst ]; then
|
||||
instcmd=:
|
||||
else
|
||||
instcmd=mkdir
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
|
||||
if [ -f $src -o -d $src ]
|
||||
then
|
||||
true
|
||||
else
|
||||
echo "install: $src does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ x"$dst" = x ]
|
||||
then
|
||||
echo "install: no destination specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# If destination is a directory, append the input filename; if your system
|
||||
# does not like double slashes in filenames, you may need to add some logic
|
||||
|
||||
if [ -d $dst ]
|
||||
then
|
||||
dst="$dst"/`basename $src`
|
||||
else
|
||||
true
|
||||
fi
|
||||
fi
|
||||
|
||||
## this sed command emulates the dirname command
|
||||
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||
|
||||
# Make sure that the destination directory exists.
|
||||
# this part is taken from Noah Friedman's mkinstalldirs script
|
||||
|
||||
# Skip lots of stat calls in the usual case.
|
||||
if [ ! -d "$dstdir" ]; then
|
||||
defaultIFS='
|
||||
'
|
||||
IFS="${IFS-${defaultIFS}}"
|
||||
|
||||
oIFS="${IFS}"
|
||||
# Some sh's can't handle IFS=/ for some reason.
|
||||
IFS='%'
|
||||
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||
IFS="${oIFS}"
|
||||
|
||||
pathcomp=''
|
||||
|
||||
while [ $# -ne 0 ] ; do
|
||||
pathcomp="${pathcomp}${1}"
|
||||
shift
|
||||
|
||||
if [ ! -d "${pathcomp}" ] ;
|
||||
then
|
||||
$mkdirprog "${pathcomp}"
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
pathcomp="${pathcomp}/"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]
|
||||
then
|
||||
$doit $instcmd $dst &&
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
|
||||
else
|
||||
|
||||
# If we're going to rename the final executable, determine the name now.
|
||||
|
||||
if [ x"$transformarg" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
dstfile=`basename $dst $transformbasename |
|
||||
sed $transformarg`$transformbasename
|
||||
fi
|
||||
|
||||
# don't allow the sed command to completely eliminate the filename
|
||||
|
||||
if [ x"$dstfile" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# Make a temp file name in the proper directory.
|
||||
|
||||
dsttmp=$dstdir/#inst.$$#
|
||||
|
||||
# Move or copy the file name to the temp name
|
||||
|
||||
$doit $instcmd $src $dsttmp &&
|
||||
|
||||
trap "rm -f ${dsttmp}" 0 &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits
|
||||
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $instcmd $src $dsttmp" command.
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
|
||||
$doit $rmcmd -f $dstdir/$dstfile &&
|
||||
$doit $mvcmd $dsttmp $dstdir/$dstfile
|
||||
|
||||
fi &&
|
||||
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
a implementation of MD4 designed for use in the SMB authentication protocol
|
||||
Copyright (C) Andrew Tridgell 1997-1998.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "ccache.h"
|
||||
|
||||
/* NOTE: This code makes no attempt to be fast!
|
||||
|
||||
It assumes that a int is at least 32 bits long
|
||||
*/
|
||||
|
||||
static struct mdfour *m;
|
||||
|
||||
#define MASK32 (0xffffffff)
|
||||
|
||||
#define F(X,Y,Z) ((((X)&(Y)) | ((~(X))&(Z))))
|
||||
#define G(X,Y,Z) ((((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z))))
|
||||
#define H(X,Y,Z) (((X)^(Y)^(Z)))
|
||||
#define lshift(x,s) (((((x)<<(s))&MASK32) | (((x)>>(32-(s)))&MASK32)))
|
||||
|
||||
#define ROUND1(a,b,c,d,k,s) a = lshift((a + F(b,c,d) + M[k])&MASK32, s)
|
||||
#define ROUND2(a,b,c,d,k,s) a = lshift((a + G(b,c,d) + M[k] + 0x5A827999)&MASK32,s)
|
||||
#define ROUND3(a,b,c,d,k,s) a = lshift((a + H(b,c,d) + M[k] + 0x6ED9EBA1)&MASK32,s)
|
||||
|
||||
/* this applies md4 to 64 byte chunks */
|
||||
static void mdfour64(uint32 *M)
|
||||
{
|
||||
uint32 AA, BB, CC, DD;
|
||||
uint32 A,B,C,D;
|
||||
|
||||
A = m->A; B = m->B; C = m->C; D = m->D;
|
||||
AA = A; BB = B; CC = C; DD = D;
|
||||
|
||||
ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7);
|
||||
ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19);
|
||||
ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7);
|
||||
ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19);
|
||||
ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7);
|
||||
ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19);
|
||||
ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7);
|
||||
ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19);
|
||||
|
||||
|
||||
ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5);
|
||||
ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13);
|
||||
ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5);
|
||||
ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13);
|
||||
ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5);
|
||||
ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13);
|
||||
ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5);
|
||||
ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13);
|
||||
|
||||
ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9);
|
||||
ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15);
|
||||
ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9);
|
||||
ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15);
|
||||
ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9);
|
||||
ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15);
|
||||
ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9);
|
||||
ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15);
|
||||
|
||||
A += AA; B += BB;
|
||||
C += CC; D += DD;
|
||||
|
||||
A &= MASK32; B &= MASK32;
|
||||
C &= MASK32; D &= MASK32;
|
||||
|
||||
m->A = A; m->B = B; m->C = C; m->D = D;
|
||||
}
|
||||
|
||||
static void copy64(uint32 *M, const unsigned char *in)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;i<16;i++)
|
||||
M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
|
||||
(in[i*4+1]<<8) | (in[i*4+0]<<0);
|
||||
}
|
||||
|
||||
static void copy4(unsigned char *out,uint32 x)
|
||||
{
|
||||
out[0] = x&0xFF;
|
||||
out[1] = (x>>8)&0xFF;
|
||||
out[2] = (x>>16)&0xFF;
|
||||
out[3] = (x>>24)&0xFF;
|
||||
}
|
||||
|
||||
void mdfour_begin(struct mdfour *md)
|
||||
{
|
||||
md->A = 0x67452301;
|
||||
md->B = 0xefcdab89;
|
||||
md->C = 0x98badcfe;
|
||||
md->D = 0x10325476;
|
||||
md->totalN = 0;
|
||||
md->tail_len = 0;
|
||||
}
|
||||
|
||||
|
||||
static void mdfour_tail(const unsigned char *in, int n)
|
||||
{
|
||||
unsigned char buf[128];
|
||||
uint32 M[16];
|
||||
uint32 b;
|
||||
|
||||
m->totalN += n;
|
||||
|
||||
b = m->totalN * 8;
|
||||
|
||||
memset(buf, 0, 128);
|
||||
if (n) memcpy(buf, in, n);
|
||||
buf[n] = 0x80;
|
||||
|
||||
if (n <= 55) {
|
||||
copy4(buf+56, b);
|
||||
copy64(M, buf);
|
||||
mdfour64(M);
|
||||
} else {
|
||||
copy4(buf+120, b);
|
||||
copy64(M, buf);
|
||||
mdfour64(M);
|
||||
copy64(M, buf+64);
|
||||
mdfour64(M);
|
||||
}
|
||||
}
|
||||
|
||||
void mdfour_update(struct mdfour *md, const unsigned char *in, int n)
|
||||
{
|
||||
uint32 M[16];
|
||||
|
||||
m = md;
|
||||
|
||||
if (in == NULL) {
|
||||
mdfour_tail(md->tail, md->tail_len);
|
||||
return;
|
||||
}
|
||||
|
||||
if (md->tail_len) {
|
||||
int len = 64 - md->tail_len;
|
||||
if (len > n) len = n;
|
||||
memcpy(md->tail+md->tail_len, in, len);
|
||||
md->tail_len += len;
|
||||
n -= len;
|
||||
in += len;
|
||||
if (md->tail_len == 64) {
|
||||
copy64(M, md->tail);
|
||||
mdfour64(M);
|
||||
m->totalN += 64;
|
||||
md->tail_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
while (n >= 64) {
|
||||
copy64(M, in);
|
||||
mdfour64(M);
|
||||
in += 64;
|
||||
n -= 64;
|
||||
m->totalN += 64;
|
||||
}
|
||||
|
||||
if (n) {
|
||||
memcpy(md->tail, in, n);
|
||||
md->tail_len = n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mdfour_result(struct mdfour *md, unsigned char *out)
|
||||
{
|
||||
m = md;
|
||||
|
||||
copy4(out, m->A);
|
||||
copy4(out+4, m->B);
|
||||
copy4(out+8, m->C);
|
||||
copy4(out+12, m->D);
|
||||
}
|
||||
|
||||
|
||||
void mdfour(unsigned char *out, const unsigned char *in, int n)
|
||||
{
|
||||
struct mdfour md;
|
||||
mdfour_begin(&md);
|
||||
mdfour_update(&md, in, n);
|
||||
mdfour_update(&md, NULL, 0);
|
||||
mdfour_result(&md, out);
|
||||
}
|
||||
|
||||
#ifdef TEST_MDFOUR
|
||||
static void file_checksum1(char *fname)
|
||||
{
|
||||
int fd, i;
|
||||
struct mdfour md;
|
||||
unsigned char buf[1024], sum[16];
|
||||
unsigned chunk;
|
||||
|
||||
fd = open(fname,O_RDONLY|O_BINARY);
|
||||
if (fd == -1) {
|
||||
perror("fname");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
chunk = 1 + random() % (sizeof(buf) - 1);
|
||||
|
||||
mdfour_begin(&md);
|
||||
|
||||
while (1) {
|
||||
int n = read(fd, buf, chunk);
|
||||
if (n >= 0) {
|
||||
mdfour_update(&md, buf, n);
|
||||
}
|
||||
if (n < chunk) break;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
mdfour_update(&md, NULL, 0);
|
||||
|
||||
mdfour_result(&md, sum);
|
||||
|
||||
for (i=0;i<16;i++)
|
||||
printf("%02x", sum[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#if 0
|
||||
#include "../md4.h"
|
||||
|
||||
static void file_checksum2(char *fname)
|
||||
{
|
||||
int fd, i;
|
||||
MDstruct md;
|
||||
unsigned char buf[64], sum[16];
|
||||
|
||||
fd = open(fname,O_RDONLY|O_BINARY);
|
||||
if (fd == -1) {
|
||||
perror("fname");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
MDbegin(&md);
|
||||
|
||||
while (1) {
|
||||
int n = read(fd, buf, sizeof(buf));
|
||||
if (n <= 0) break;
|
||||
MDupdate(&md, buf, n*8);
|
||||
}
|
||||
|
||||
if (!md.done) {
|
||||
MDupdate(&md, buf, 0);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
memcpy(sum, md.buffer, 16);
|
||||
|
||||
for (i=0;i<16;i++)
|
||||
printf("%02x", sum[i]);
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
file_checksum1(argv[1]);
|
||||
#if 0
|
||||
file_checksum2(argv[1]);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 1.9.
|
||||
a implementation of MD4 designed for use in the SMB authentication protocol
|
||||
Copyright (C) Andrew Tridgell 1997-1998.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
struct mdfour {
|
||||
uint32 A, B, C, D;
|
||||
uint32 totalN;
|
||||
unsigned char tail[64];
|
||||
unsigned tail_len;
|
||||
};
|
||||
|
||||
void mdfour_begin(struct mdfour *md);
|
||||
void mdfour_update(struct mdfour *md, const unsigned char *in, int n);
|
||||
void mdfour_result(struct mdfour *md, unsigned char *out);
|
||||
void mdfour(unsigned char *out, const unsigned char *in, int n);
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
These packaging files are contributd by users of ccache. I do not
|
||||
maintain them, and they may well need updating before you use them.
|
||||
|
||||
I don't distribute binary packages of ccache myself, but if you wish
|
||||
to add ccache to a distribution then that's OK
|
|
@ -0,0 +1,37 @@
|
|||
Summary: Compiler Cache
|
||||
Name: ccache
|
||||
Version: 2.3
|
||||
Release: 1
|
||||
Group: Development/Languages
|
||||
License: GPL
|
||||
URL: http://ccache.samba.org/
|
||||
Source: ccache-%{version}.tar.gz
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-root
|
||||
|
||||
%description
|
||||
ccache caches gcc output files
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
%configure
|
||||
make
|
||||
|
||||
install -d -m 0755 $RPM_BUILD_ROOT%{_bindir}
|
||||
install -m 0755 ccache $RPM_BUILD_ROOT%{_bindir}
|
||||
install -d -m 0755 $RPM_BUILD_ROOT%{_mandir}/man1
|
||||
install -m 0644 ccache.1 $RPM_BUILD_ROOT%{_mandir}/man1
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
%doc README
|
||||
%{_mandir}/man1/ccache.1*
|
||||
%{_bindir}/ccache
|
||||
|
||||
%clean
|
||||
[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%changelog
|
||||
* Mon Apr 01 2002 Peter Jones <pjones@redhat.com>
|
||||
- Created the package
|
|
@ -0,0 +1,965 @@
|
|||
/*
|
||||
* Copyright Patrick Powell 1995
|
||||
* This code is based on code written by Patrick Powell (papowell@astart.com)
|
||||
* It may be used for any purpose as long as this notice remains intact
|
||||
* on all source code distributions
|
||||
*/
|
||||
|
||||
/**************************************************************
|
||||
* Original:
|
||||
* Patrick Powell Tue Apr 11 09:48:21 PDT 1995
|
||||
* A bombproof version of doprnt (dopr) included.
|
||||
* Sigh. This sort of thing is always nasty do deal with. Note that
|
||||
* the version here does not include floating point...
|
||||
*
|
||||
* snprintf() is used instead of sprintf() as it does limit checks
|
||||
* for string length. This covers a nasty loophole.
|
||||
*
|
||||
* The other functions are there to prevent NULL pointers from
|
||||
* causing nast effects.
|
||||
*
|
||||
* More Recently:
|
||||
* Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
|
||||
* This was ugly. It is still ugly. I opted out of floating point
|
||||
* numbers, but the formatter understands just about everything
|
||||
* from the normal C string format, at least as far as I can tell from
|
||||
* the Solaris 2.5 printf(3S) man page.
|
||||
*
|
||||
* Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
|
||||
* Ok, added some minimal floating point support, which means this
|
||||
* probably requires libm on most operating systems. Don't yet
|
||||
* support the exponent (e,E) and sigfig (g,G). Also, fmtint()
|
||||
* was pretty badly broken, it just wasn't being exercised in ways
|
||||
* which showed it, so that's been fixed. Also, formated the code
|
||||
* to mutt conventions, and removed dead code left over from the
|
||||
* original. Also, there is now a builtin-test, just compile with:
|
||||
* gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
|
||||
* and run snprintf for results.
|
||||
*
|
||||
* Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
|
||||
* The PGP code was using unsigned hexadecimal formats.
|
||||
* Unfortunately, unsigned formats simply didn't work.
|
||||
*
|
||||
* Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
|
||||
* The original code assumed that both snprintf() and vsnprintf() were
|
||||
* missing. Some systems only have snprintf() but not vsnprintf(), so
|
||||
* the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
|
||||
*
|
||||
* Andrew Tridgell (tridge@samba.org) Oct 1998
|
||||
* fixed handling of %.0f
|
||||
* added test for HAVE_LONG_DOUBLE
|
||||
*
|
||||
* tridge@samba.org, idra@samba.org, April 2001
|
||||
* got rid of fcvt code (twas buggy and made testing harder)
|
||||
* added C99 semantics
|
||||
*
|
||||
**************************************************************/
|
||||
|
||||
#ifndef NO_CONFIG_H /* for some tests */
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#ifdef HAVE_CTYPE_H
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
|
||||
/* only include stdio.h if we are not re-defining snprintf or vsnprintf */
|
||||
#include <stdio.h>
|
||||
/* make the compiler happy with an empty file */
|
||||
void dummy_snprintf(void) {}
|
||||
#else
|
||||
|
||||
#ifdef HAVE_LONG_DOUBLE
|
||||
#define LDOUBLE long double
|
||||
#else
|
||||
#define LDOUBLE double
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LONG_LONG
|
||||
#define LLONG long long
|
||||
#else
|
||||
#define LLONG long
|
||||
#endif
|
||||
|
||||
static size_t dopr(char *buffer, size_t maxlen, const char *format,
|
||||
va_list args);
|
||||
static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
|
||||
char *value, int flags, int min, int max);
|
||||
static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
|
||||
long value, int base, int min, int max, int flags);
|
||||
static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
|
||||
LDOUBLE fvalue, int min, int max, int flags);
|
||||
static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
|
||||
|
||||
/*
|
||||
* dopr(): poor man's version of doprintf
|
||||
*/
|
||||
|
||||
/* format read states */
|
||||
#define DP_S_DEFAULT 0
|
||||
#define DP_S_FLAGS 1
|
||||
#define DP_S_MIN 2
|
||||
#define DP_S_DOT 3
|
||||
#define DP_S_MAX 4
|
||||
#define DP_S_MOD 5
|
||||
#define DP_S_CONV 6
|
||||
#define DP_S_DONE 7
|
||||
|
||||
/* format flags - Bits */
|
||||
#define DP_F_MINUS (1 << 0)
|
||||
#define DP_F_PLUS (1 << 1)
|
||||
#define DP_F_SPACE (1 << 2)
|
||||
#define DP_F_NUM (1 << 3)
|
||||
#define DP_F_ZERO (1 << 4)
|
||||
#define DP_F_UP (1 << 5)
|
||||
#define DP_F_UNSIGNED (1 << 6)
|
||||
|
||||
/* Conversion Flags */
|
||||
#define DP_C_SHORT 1
|
||||
#define DP_C_LONG 2
|
||||
#define DP_C_LDOUBLE 3
|
||||
#define DP_C_LLONG 4
|
||||
|
||||
#define char_to_int(p) ((p)- '0')
|
||||
#ifndef MAX
|
||||
#define MAX(p,q) (((p) >= (q)) ? (p) : (q))
|
||||
#endif
|
||||
|
||||
static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args)
|
||||
{
|
||||
char ch;
|
||||
LLONG value;
|
||||
LDOUBLE fvalue;
|
||||
char *strvalue;
|
||||
int min;
|
||||
int max;
|
||||
int state;
|
||||
int flags;
|
||||
int cflags;
|
||||
size_t currlen;
|
||||
|
||||
state = DP_S_DEFAULT;
|
||||
currlen = flags = cflags = min = 0;
|
||||
max = -1;
|
||||
ch = *format++;
|
||||
|
||||
while (state != DP_S_DONE) {
|
||||
if (ch == '\0')
|
||||
state = DP_S_DONE;
|
||||
|
||||
switch(state) {
|
||||
case DP_S_DEFAULT:
|
||||
if (ch == '%')
|
||||
state = DP_S_FLAGS;
|
||||
else
|
||||
dopr_outch (buffer, &currlen, maxlen, ch);
|
||||
ch = *format++;
|
||||
break;
|
||||
case DP_S_FLAGS:
|
||||
switch (ch) {
|
||||
case '-':
|
||||
flags |= DP_F_MINUS;
|
||||
ch = *format++;
|
||||
break;
|
||||
case '+':
|
||||
flags |= DP_F_PLUS;
|
||||
ch = *format++;
|
||||
break;
|
||||
case ' ':
|
||||
flags |= DP_F_SPACE;
|
||||
ch = *format++;
|
||||
break;
|
||||
case '#':
|
||||
flags |= DP_F_NUM;
|
||||
ch = *format++;
|
||||
break;
|
||||
case '0':
|
||||
flags |= DP_F_ZERO;
|
||||
ch = *format++;
|
||||
break;
|
||||
default:
|
||||
state = DP_S_MIN;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case DP_S_MIN:
|
||||
if (isdigit((unsigned char)ch)) {
|
||||
min = 10*min + char_to_int (ch);
|
||||
ch = *format++;
|
||||
} else if (ch == '*') {
|
||||
min = va_arg (args, int);
|
||||
ch = *format++;
|
||||
state = DP_S_DOT;
|
||||
} else {
|
||||
state = DP_S_DOT;
|
||||
}
|
||||
break;
|
||||
case DP_S_DOT:
|
||||
if (ch == '.') {
|
||||
state = DP_S_MAX;
|
||||
ch = *format++;
|
||||
} else {
|
||||
state = DP_S_MOD;
|
||||
}
|
||||
break;
|
||||
case DP_S_MAX:
|
||||
if (isdigit((unsigned char)ch)) {
|
||||
if (max < 0)
|
||||
max = 0;
|
||||
max = 10*max + char_to_int (ch);
|
||||
ch = *format++;
|
||||
} else if (ch == '*') {
|
||||
max = va_arg (args, int);
|
||||
ch = *format++;
|
||||
state = DP_S_MOD;
|
||||
} else {
|
||||
state = DP_S_MOD;
|
||||
}
|
||||
break;
|
||||
case DP_S_MOD:
|
||||
switch (ch) {
|
||||
case 'h':
|
||||
cflags = DP_C_SHORT;
|
||||
ch = *format++;
|
||||
break;
|
||||
case 'l':
|
||||
cflags = DP_C_LONG;
|
||||
ch = *format++;
|
||||
if (ch == 'l') { /* It's a long long */
|
||||
cflags = DP_C_LLONG;
|
||||
ch = *format++;
|
||||
}
|
||||
break;
|
||||
case 'L':
|
||||
cflags = DP_C_LDOUBLE;
|
||||
ch = *format++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
state = DP_S_CONV;
|
||||
break;
|
||||
case DP_S_CONV:
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
case 'i':
|
||||
if (cflags == DP_C_SHORT)
|
||||
value = va_arg (args, int);
|
||||
else if (cflags == DP_C_LONG)
|
||||
value = va_arg (args, long int);
|
||||
else if (cflags == DP_C_LLONG)
|
||||
value = va_arg (args, LLONG);
|
||||
else
|
||||
value = va_arg (args, int);
|
||||
fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
|
||||
break;
|
||||
case 'o':
|
||||
flags |= DP_F_UNSIGNED;
|
||||
if (cflags == DP_C_SHORT)
|
||||
value = va_arg (args, unsigned int);
|
||||
else if (cflags == DP_C_LONG)
|
||||
value = (long)va_arg (args, unsigned long int);
|
||||
else if (cflags == DP_C_LLONG)
|
||||
value = (long)va_arg (args, unsigned LLONG);
|
||||
else
|
||||
value = (long)va_arg (args, unsigned int);
|
||||
fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
|
||||
break;
|
||||
case 'u':
|
||||
flags |= DP_F_UNSIGNED;
|
||||
if (cflags == DP_C_SHORT)
|
||||
value = va_arg (args, unsigned int);
|
||||
else if (cflags == DP_C_LONG)
|
||||
value = (long)va_arg (args, unsigned long int);
|
||||
else if (cflags == DP_C_LLONG)
|
||||
value = (LLONG)va_arg (args, unsigned LLONG);
|
||||
else
|
||||
value = (long)va_arg (args, unsigned int);
|
||||
fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
|
||||
break;
|
||||
case 'X':
|
||||
flags |= DP_F_UP;
|
||||
/* FALLTHROUGH */
|
||||
case 'x':
|
||||
flags |= DP_F_UNSIGNED;
|
||||
if (cflags == DP_C_SHORT)
|
||||
value = va_arg (args, unsigned int);
|
||||
else if (cflags == DP_C_LONG)
|
||||
value = (long)va_arg (args, unsigned long int);
|
||||
else if (cflags == DP_C_LLONG)
|
||||
value = (LLONG)va_arg (args, unsigned LLONG);
|
||||
else
|
||||
value = (long)va_arg (args, unsigned int);
|
||||
fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
|
||||
break;
|
||||
case 'f':
|
||||
if (cflags == DP_C_LDOUBLE)
|
||||
fvalue = va_arg (args, LDOUBLE);
|
||||
else
|
||||
fvalue = va_arg (args, double);
|
||||
/* um, floating point? */
|
||||
fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
|
||||
break;
|
||||
case 'E':
|
||||
flags |= DP_F_UP;
|
||||
/* FALLTHROUGH */
|
||||
case 'e':
|
||||
if (cflags == DP_C_LDOUBLE)
|
||||
fvalue = va_arg (args, LDOUBLE);
|
||||
else
|
||||
fvalue = va_arg (args, double);
|
||||
break;
|
||||
case 'G':
|
||||
flags |= DP_F_UP;
|
||||
/* FALLTHROUGH */
|
||||
case 'g':
|
||||
if (cflags == DP_C_LDOUBLE)
|
||||
fvalue = va_arg (args, LDOUBLE);
|
||||
else
|
||||
fvalue = va_arg (args, double);
|
||||
break;
|
||||
case 'c':
|
||||
dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
|
||||
break;
|
||||
case 's':
|
||||
strvalue = va_arg (args, char *);
|
||||
if (!strvalue) strvalue = "(NULL)";
|
||||
if (max == -1) {
|
||||
max = strlen(strvalue);
|
||||
}
|
||||
if (min > 0 && max >= 0 && min > max) max = min;
|
||||
fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
|
||||
break;
|
||||
case 'p':
|
||||
strvalue = (char *)va_arg(args, void *);
|
||||
fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
|
||||
break;
|
||||
case 'n':
|
||||
if (cflags == DP_C_SHORT) {
|
||||
short int *num;
|
||||
num = va_arg (args, short int *);
|
||||
*num = currlen;
|
||||
} else if (cflags == DP_C_LONG) {
|
||||
long int *num;
|
||||
num = va_arg (args, long int *);
|
||||
*num = (long int)currlen;
|
||||
} else if (cflags == DP_C_LLONG) {
|
||||
LLONG *num;
|
||||
num = va_arg (args, LLONG *);
|
||||
*num = (LLONG)currlen;
|
||||
} else {
|
||||
int *num;
|
||||
num = va_arg (args, int *);
|
||||
*num = currlen;
|
||||
}
|
||||
break;
|
||||
case '%':
|
||||
dopr_outch (buffer, &currlen, maxlen, ch);
|
||||
break;
|
||||
case 'w':
|
||||
/* not supported yet, treat as next char */
|
||||
ch = *format++;
|
||||
break;
|
||||
default:
|
||||
/* Unknown, skip */
|
||||
break;
|
||||
}
|
||||
ch = *format++;
|
||||
state = DP_S_DEFAULT;
|
||||
flags = cflags = min = 0;
|
||||
max = -1;
|
||||
break;
|
||||
case DP_S_DONE:
|
||||
break;
|
||||
default:
|
||||
/* hmm? */
|
||||
break; /* some picky compilers need this */
|
||||
}
|
||||
}
|
||||
if (maxlen != 0) {
|
||||
if (currlen < maxlen - 1)
|
||||
buffer[currlen] = '\0';
|
||||
else if (maxlen > 0)
|
||||
buffer[maxlen - 1] = '\0';
|
||||
}
|
||||
|
||||
return currlen;
|
||||
}
|
||||
|
||||
static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
|
||||
char *value, int flags, int min, int max)
|
||||
{
|
||||
int padlen, strln; /* amount to pad */
|
||||
int cnt = 0;
|
||||
|
||||
#ifdef DEBUG_SNPRINTF
|
||||
printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
|
||||
#endif
|
||||
if (value == 0) {
|
||||
value = "<NULL>";
|
||||
}
|
||||
|
||||
for (strln = 0; value[strln]; ++strln); /* strlen */
|
||||
padlen = min - strln;
|
||||
if (padlen < 0)
|
||||
padlen = 0;
|
||||
if (flags & DP_F_MINUS)
|
||||
padlen = -padlen; /* Left Justify */
|
||||
|
||||
while ((padlen > 0) && (cnt < max)) {
|
||||
dopr_outch (buffer, currlen, maxlen, ' ');
|
||||
--padlen;
|
||||
++cnt;
|
||||
}
|
||||
while (*value && (cnt < max)) {
|
||||
dopr_outch (buffer, currlen, maxlen, *value++);
|
||||
++cnt;
|
||||
}
|
||||
while ((padlen < 0) && (cnt < max)) {
|
||||
dopr_outch (buffer, currlen, maxlen, ' ');
|
||||
++padlen;
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
|
||||
/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
|
||||
|
||||
static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
|
||||
long value, int base, int min, int max, int flags)
|
||||
{
|
||||
int signvalue = 0;
|
||||
unsigned long uvalue;
|
||||
char convert[20];
|
||||
int place = 0;
|
||||
int spadlen = 0; /* amount to space pad */
|
||||
int zpadlen = 0; /* amount to zero pad */
|
||||
int caps = 0;
|
||||
|
||||
if (max < 0)
|
||||
max = 0;
|
||||
|
||||
uvalue = value;
|
||||
|
||||
if(!(flags & DP_F_UNSIGNED)) {
|
||||
if( value < 0 ) {
|
||||
signvalue = '-';
|
||||
uvalue = -value;
|
||||
} else {
|
||||
if (flags & DP_F_PLUS) /* Do a sign (+/i) */
|
||||
signvalue = '+';
|
||||
else if (flags & DP_F_SPACE)
|
||||
signvalue = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
|
||||
|
||||
do {
|
||||
convert[place++] =
|
||||
(caps? "0123456789ABCDEF":"0123456789abcdef")
|
||||
[uvalue % (unsigned)base ];
|
||||
uvalue = (uvalue / (unsigned)base );
|
||||
} while(uvalue && (place < 20));
|
||||
if (place == 20) place--;
|
||||
convert[place] = 0;
|
||||
|
||||
zpadlen = max - place;
|
||||
spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
|
||||
if (zpadlen < 0) zpadlen = 0;
|
||||
if (spadlen < 0) spadlen = 0;
|
||||
if (flags & DP_F_ZERO) {
|
||||
zpadlen = MAX(zpadlen, spadlen);
|
||||
spadlen = 0;
|
||||
}
|
||||
if (flags & DP_F_MINUS)
|
||||
spadlen = -spadlen; /* Left Justifty */
|
||||
|
||||
#ifdef DEBUG_SNPRINTF
|
||||
printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
|
||||
zpadlen, spadlen, min, max, place);
|
||||
#endif
|
||||
|
||||
/* Spaces */
|
||||
while (spadlen > 0) {
|
||||
dopr_outch (buffer, currlen, maxlen, ' ');
|
||||
--spadlen;
|
||||
}
|
||||
|
||||
/* Sign */
|
||||
if (signvalue)
|
||||
dopr_outch (buffer, currlen, maxlen, signvalue);
|
||||
|
||||
/* Zeros */
|
||||
if (zpadlen > 0) {
|
||||
while (zpadlen > 0) {
|
||||
dopr_outch (buffer, currlen, maxlen, '0');
|
||||
--zpadlen;
|
||||
}
|
||||
}
|
||||
|
||||
/* Digits */
|
||||
while (place > 0)
|
||||
dopr_outch (buffer, currlen, maxlen, convert[--place]);
|
||||
|
||||
/* Left Justified spaces */
|
||||
while (spadlen < 0) {
|
||||
dopr_outch (buffer, currlen, maxlen, ' ');
|
||||
++spadlen;
|
||||
}
|
||||
}
|
||||
|
||||
static LDOUBLE abs_val(LDOUBLE value)
|
||||
{
|
||||
LDOUBLE result = value;
|
||||
|
||||
if (value < 0)
|
||||
result = -value;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static LDOUBLE POW10(int exp)
|
||||
{
|
||||
LDOUBLE result = 1;
|
||||
|
||||
while (exp) {
|
||||
result *= 10;
|
||||
exp--;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static LLONG ROUND(LDOUBLE value)
|
||||
{
|
||||
LLONG intpart;
|
||||
|
||||
intpart = (LLONG)value;
|
||||
value = value - intpart;
|
||||
if (value >= 0.5) intpart++;
|
||||
|
||||
return intpart;
|
||||
}
|
||||
|
||||
/* a replacement for modf that doesn't need the math library. Should
|
||||
be portable, but slow */
|
||||
static double my_modf(double x0, double *iptr)
|
||||
{
|
||||
int i;
|
||||
long l;
|
||||
double x = x0;
|
||||
double f = 1.0;
|
||||
|
||||
for (i=0;i<100;i++) {
|
||||
l = (long)x;
|
||||
if (l <= (x+1) && l >= (x-1)) break;
|
||||
x *= 0.1;
|
||||
f *= 10.0;
|
||||
}
|
||||
|
||||
if (i == 100) {
|
||||
/* yikes! the number is beyond what we can handle. What do we do? */
|
||||
(*iptr) = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (i != 0) {
|
||||
double i2;
|
||||
double ret;
|
||||
|
||||
ret = my_modf(x0-l*f, &i2);
|
||||
(*iptr) = l*f + i2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
(*iptr) = l;
|
||||
return x - (*iptr);
|
||||
}
|
||||
|
||||
|
||||
static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
||||
LDOUBLE fvalue, int min, int max, int flags)
|
||||
{
|
||||
int signvalue = 0;
|
||||
double ufvalue;
|
||||
char iconvert[311];
|
||||
char fconvert[311];
|
||||
int iplace = 0;
|
||||
int fplace = 0;
|
||||
int padlen = 0; /* amount to pad */
|
||||
int zpadlen = 0;
|
||||
int caps = 0;
|
||||
int index;
|
||||
double intpart;
|
||||
double fracpart;
|
||||
double temp;
|
||||
|
||||
/*
|
||||
* AIX manpage says the default is 0, but Solaris says the default
|
||||
* is 6, and sprintf on AIX defaults to 6
|
||||
*/
|
||||
if (max < 0)
|
||||
max = 6;
|
||||
|
||||
ufvalue = abs_val (fvalue);
|
||||
|
||||
if (fvalue < 0) {
|
||||
signvalue = '-';
|
||||
} else {
|
||||
if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
|
||||
signvalue = '+';
|
||||
} else {
|
||||
if (flags & DP_F_SPACE)
|
||||
signvalue = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Sorry, we only support 16 digits past the decimal because of our
|
||||
* conversion method
|
||||
*/
|
||||
if (max > 16)
|
||||
max = 16;
|
||||
|
||||
/* We "cheat" by converting the fractional part to integer by
|
||||
* multiplying by a factor of 10
|
||||
*/
|
||||
|
||||
temp = ufvalue;
|
||||
my_modf(temp, &intpart);
|
||||
|
||||
fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
|
||||
|
||||
if (fracpart >= POW10(max)) {
|
||||
intpart++;
|
||||
fracpart -= POW10(max);
|
||||
}
|
||||
|
||||
|
||||
/* Convert integer part */
|
||||
do {
|
||||
temp = intpart;
|
||||
my_modf(intpart*0.1, &intpart);
|
||||
temp = temp*0.1;
|
||||
index = (int) ((temp -intpart +0.05)* 10.0);
|
||||
/* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
|
||||
/* printf ("%llf, %f, %x\n", temp, intpart, index); */
|
||||
iconvert[iplace++] =
|
||||
(caps? "0123456789ABCDEF":"0123456789abcdef")[index];
|
||||
} while (intpart && (iplace < 311));
|
||||
if (iplace == 311) iplace--;
|
||||
iconvert[iplace] = 0;
|
||||
|
||||
/* Convert fractional part */
|
||||
if (fracpart)
|
||||
{
|
||||
do {
|
||||
temp = fracpart;
|
||||
my_modf(fracpart*0.1, &fracpart);
|
||||
temp = temp*0.1;
|
||||
index = (int) ((temp -fracpart +0.05)* 10.0);
|
||||
/* index = (int) ((((temp/10) -fracpart) +0.05) *10); */
|
||||
/* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */
|
||||
fconvert[fplace++] =
|
||||
(caps? "0123456789ABCDEF":"0123456789abcdef")[index];
|
||||
} while(fracpart && (fplace < 311));
|
||||
if (fplace == 311) fplace--;
|
||||
}
|
||||
fconvert[fplace] = 0;
|
||||
|
||||
/* -1 for decimal point, another -1 if we are printing a sign */
|
||||
padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
|
||||
zpadlen = max - fplace;
|
||||
if (zpadlen < 0) zpadlen = 0;
|
||||
if (padlen < 0)
|
||||
padlen = 0;
|
||||
if (flags & DP_F_MINUS)
|
||||
padlen = -padlen; /* Left Justifty */
|
||||
|
||||
if ((flags & DP_F_ZERO) && (padlen > 0)) {
|
||||
if (signvalue) {
|
||||
dopr_outch (buffer, currlen, maxlen, signvalue);
|
||||
--padlen;
|
||||
signvalue = 0;
|
||||
}
|
||||
while (padlen > 0) {
|
||||
dopr_outch (buffer, currlen, maxlen, '0');
|
||||
--padlen;
|
||||
}
|
||||
}
|
||||
while (padlen > 0) {
|
||||
dopr_outch (buffer, currlen, maxlen, ' ');
|
||||
--padlen;
|
||||
}
|
||||
if (signvalue)
|
||||
dopr_outch (buffer, currlen, maxlen, signvalue);
|
||||
|
||||
while (iplace > 0)
|
||||
dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
|
||||
|
||||
#ifdef DEBUG_SNPRINTF
|
||||
printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Decimal point. This should probably use locale to find the correct
|
||||
* char to print out.
|
||||
*/
|
||||
if (max > 0) {
|
||||
dopr_outch (buffer, currlen, maxlen, '.');
|
||||
|
||||
while (fplace > 0)
|
||||
dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
|
||||
}
|
||||
|
||||
while (zpadlen > 0) {
|
||||
dopr_outch (buffer, currlen, maxlen, '0');
|
||||
--zpadlen;
|
||||
}
|
||||
|
||||
while (padlen < 0) {
|
||||
dopr_outch (buffer, currlen, maxlen, ' ');
|
||||
++padlen;
|
||||
}
|
||||
}
|
||||
|
||||
static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
|
||||
{
|
||||
if (*currlen < maxlen) {
|
||||
buffer[(*currlen)] = c;
|
||||
}
|
||||
(*currlen)++;
|
||||
}
|
||||
|
||||
/* yes this really must be a ||. Don't muck with this (tridge) */
|
||||
#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
|
||||
int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
|
||||
{
|
||||
return dopr(str, count, fmt, args);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* yes this really must be a ||. Don't muck wiith this (tridge)
|
||||
*
|
||||
* The logic for these two is that we need our own definition if the
|
||||
* OS *either* has no definition of *sprintf, or if it does have one
|
||||
* that doesn't work properly according to the autoconf test. Perhaps
|
||||
* these should really be smb_snprintf to avoid conflicts with buggy
|
||||
* linkers? -- mbp
|
||||
*/
|
||||
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_SNPRINTF)
|
||||
int snprintf(char *str,size_t count,const char *fmt,...)
|
||||
{
|
||||
size_t ret;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = vsnprintf(str, count, fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_VASPRINTF
|
||||
int vasprintf(char **ptr, const char *format, va_list ap)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = vsnprintf(0, 0, format, ap);
|
||||
if (ret <= 0) return ret;
|
||||
|
||||
(*ptr) = (char *)malloc(ret+1);
|
||||
if (!*ptr) return -1;
|
||||
ret = vsnprintf(*ptr, ret+1, format, ap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HAVE_ASPRINTF
|
||||
int asprintf(char **ptr, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
*ptr = 0;
|
||||
va_start(ap, format);
|
||||
ret = vasprintf(ptr, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_VSYSLOG
|
||||
#ifdef HAVE_SYSLOG
|
||||
void vsyslog (int facility_priority, char *format, va_list arglist)
|
||||
{
|
||||
char *msg = 0;
|
||||
vasprintf(&msg, format, arglist);
|
||||
if (!msg)
|
||||
return;
|
||||
syslog(facility_priority, "%s", msg);
|
||||
free(msg);
|
||||
}
|
||||
#endif /* HAVE_SYSLOG */
|
||||
#endif /* HAVE_VSYSLOG */
|
||||
|
||||
#ifdef TEST_SNPRINTF
|
||||
|
||||
int sprintf(char *str,const char *fmt,...);
|
||||
|
||||
int main (void)
|
||||
{
|
||||
char buf1[1024];
|
||||
char buf2[1024];
|
||||
char *fp_fmt[] = {
|
||||
"%1.1f",
|
||||
"%-1.5f",
|
||||
"%1.5f",
|
||||
"%123.9f",
|
||||
"%10.5f",
|
||||
"% 10.5f",
|
||||
"%+22.9f",
|
||||
"%+4.9f",
|
||||
"%01.3f",
|
||||
"%4f",
|
||||
"%3.1f",
|
||||
"%3.2f",
|
||||
"%.0f",
|
||||
"%f",
|
||||
"-16.16f",
|
||||
0
|
||||
};
|
||||
double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
|
||||
0.9996, 1.996, 4.136, 0};
|
||||
char *int_fmt[] = {
|
||||
"%-1.5d",
|
||||
"%1.5d",
|
||||
"%123.9d",
|
||||
"%5.5d",
|
||||
"%10.5d",
|
||||
"% 10.5d",
|
||||
"%+22.33d",
|
||||
"%01.3d",
|
||||
"%4d",
|
||||
"%d",
|
||||
0
|
||||
};
|
||||
long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
|
||||
char *str_fmt[] = {
|
||||
"10.5s",
|
||||
"5.10s",
|
||||
"10.1s",
|
||||
"0.10s",
|
||||
"10.0s",
|
||||
"1.10s",
|
||||
"%s",
|
||||
"%.1s",
|
||||
"%.10s",
|
||||
"%10s",
|
||||
0
|
||||
};
|
||||
char *str_vals[] = {"hello", "a", "", "a longer string", 0};
|
||||
int x, y;
|
||||
int fail = 0;
|
||||
int num = 0;
|
||||
|
||||
printf ("Testing snprintf format codes against system sprintf...\n");
|
||||
|
||||
for (x = 0; fp_fmt[x] ; x++) {
|
||||
for (y = 0; fp_nums[y] != 0 ; y++) {
|
||||
int l1 = snprintf(0, 0, fp_fmt[x], fp_nums[y]);
|
||||
int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
|
||||
sprintf (buf2, fp_fmt[x], fp_nums[y]);
|
||||
if (strcmp (buf1, buf2)) {
|
||||
printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
|
||||
fp_fmt[x], buf1, buf2);
|
||||
fail++;
|
||||
}
|
||||
if (l1 != l2) {
|
||||
printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]);
|
||||
fail++;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
for (x = 0; int_fmt[x] ; x++) {
|
||||
for (y = 0; int_nums[y] != 0 ; y++) {
|
||||
int l1 = snprintf(0, 0, int_fmt[x], int_nums[y]);
|
||||
int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
|
||||
sprintf (buf2, int_fmt[x], int_nums[y]);
|
||||
if (strcmp (buf1, buf2)) {
|
||||
printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
|
||||
int_fmt[x], buf1, buf2);
|
||||
fail++;
|
||||
}
|
||||
if (l1 != l2) {
|
||||
printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]);
|
||||
fail++;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
for (x = 0; str_fmt[x] ; x++) {
|
||||
for (y = 0; str_vals[y] != 0 ; y++) {
|
||||
int l1 = snprintf(0, 0, str_fmt[x], str_vals[y]);
|
||||
int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
|
||||
sprintf (buf2, str_fmt[x], str_vals[y]);
|
||||
if (strcmp (buf1, buf2)) {
|
||||
printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
|
||||
str_fmt[x], buf1, buf2);
|
||||
fail++;
|
||||
}
|
||||
if (l1 != l2) {
|
||||
printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]);
|
||||
fail++;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
printf ("%d tests failed out of %d.\n", fail, num);
|
||||
|
||||
printf("seeing how many digits we support\n");
|
||||
{
|
||||
double v0 = 0.12345678901234567890123456789012345678901;
|
||||
for (x=0; x<100; x++) {
|
||||
snprintf(buf1, sizeof(buf1), "%1.1f", v0*pow(10, x));
|
||||
sprintf(buf2, "%1.1f", v0*pow(10, x));
|
||||
if (strcmp(buf1, buf2)) {
|
||||
printf("we seem to support %d digits\n", x-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* SNPRINTF_TEST */
|
|
@ -0,0 +1,365 @@
|
|||
/*
|
||||
Copyright (C) Andrew Tridgell 2002
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/*
|
||||
routines to handle the stats files
|
||||
|
||||
the stats file is stored one per cache subdirectory to make this more
|
||||
scalable
|
||||
*/
|
||||
|
||||
#include "ccache.h"
|
||||
|
||||
extern char *stats_file;
|
||||
extern char *cache_dir;
|
||||
|
||||
#define STATS_VERSION 1
|
||||
|
||||
#define FLAG_NOZERO 1 /* don't zero with the -z option */
|
||||
#define FLAG_ALWAYS 2 /* always show, even if zero */
|
||||
|
||||
static struct {
|
||||
enum stats stat;
|
||||
char *message;
|
||||
void (*fn)(unsigned );
|
||||
unsigned flags;
|
||||
} stats_info[] = {
|
||||
{ STATS_CACHED, "cache hit ", NULL, FLAG_ALWAYS },
|
||||
{ STATS_TOCACHE, "cache miss ", NULL, FLAG_ALWAYS },
|
||||
{ STATS_LINK, "called for link ", NULL, 0 },
|
||||
{ STATS_MULTIPLE, "multiple source files ", NULL, 0 },
|
||||
{ STATS_STDOUT, "compiler produced stdout ", NULL, 0 },
|
||||
{ STATS_STATUS, "compile failed ", NULL, 0 },
|
||||
{ STATS_ERROR, "ccache internal error ", NULL, 0 },
|
||||
{ STATS_PREPROCESSOR, "preprocessor error ", NULL, 0 },
|
||||
{ STATS_COMPILER, "couldn't find the compiler ", NULL, 0 },
|
||||
{ STATS_MISSING, "cache file missing ", NULL, 0 },
|
||||
{ STATS_ARGS, "bad compiler arguments ", NULL, 0 },
|
||||
{ STATS_NOTC, "not a C/C++ file ", NULL, 0 },
|
||||
{ STATS_CONFTEST, "autoconf compile/link ", NULL, 0 },
|
||||
{ STATS_UNSUPPORTED, "unsupported compiler option ", NULL, 0 },
|
||||
{ STATS_OUTSTDOUT, "output to stdout ", NULL, 0 },
|
||||
{ STATS_DEVICE, "output to a non-regular file ", NULL, 0 },
|
||||
{ STATS_NOINPUT, "no input file ", NULL, 0 },
|
||||
{ STATS_ENVIRONMMENT, "error due to bad env variable ", NULL, 0 },
|
||||
{ STATS_NUMFILES, "files in cache ", NULL, FLAG_NOZERO|FLAG_ALWAYS },
|
||||
{ STATS_TOTALSIZE, "cache size ", display_size , FLAG_NOZERO|FLAG_ALWAYS },
|
||||
{ STATS_MAXFILES, "max files ", NULL, FLAG_NOZERO },
|
||||
{ STATS_MAXSIZE, "max cache size ", display_size, FLAG_NOZERO },
|
||||
{ STATS_NONE, NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
/* parse a stats file from a buffer - adding to the counters */
|
||||
static void parse_stats(unsigned counters[STATS_END], char *buf)
|
||||
{
|
||||
int i;
|
||||
char *p, *p2;
|
||||
|
||||
p = buf;
|
||||
for (i=0;i<STATS_END;i++) {
|
||||
counters[i] += strtol(p, &p2, 10);
|
||||
if (!p2 || p2 == p) break;
|
||||
p = p2;
|
||||
}
|
||||
}
|
||||
|
||||
/* write out a stats file */
|
||||
static void write_stats(int fd, unsigned counters[STATS_END])
|
||||
{
|
||||
int i;
|
||||
int len = 0;
|
||||
char buf[1024];
|
||||
|
||||
for (i=0;i<STATS_END;i++) {
|
||||
len += snprintf(buf+len, sizeof(buf)-(len+1), "%u ", counters[i]);
|
||||
if (len >= (int)sizeof(buf)-1) fatal("stats too long?!");
|
||||
}
|
||||
len += snprintf(buf+len, sizeof(buf)-(len+1), "\n");
|
||||
if (len >= (int)sizeof(buf)-1) fatal("stats too long?!");
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
if (write(fd, buf, len) == -1) fatal("could not write stats");
|
||||
}
|
||||
|
||||
|
||||
/* fill in some default stats values */
|
||||
static void stats_default(unsigned counters[STATS_END])
|
||||
{
|
||||
counters[STATS_MAXSIZE] += DEFAULT_MAXSIZE / 16;
|
||||
}
|
||||
|
||||
/* read in the stats from one dir and add to the counters */
|
||||
static void stats_read_fd(int fd, unsigned counters[STATS_END])
|
||||
{
|
||||
char buf[1024];
|
||||
int len;
|
||||
len = read(fd, buf, sizeof(buf)-1);
|
||||
if (len <= 0) {
|
||||
stats_default(counters);
|
||||
return;
|
||||
}
|
||||
buf[len] = 0;
|
||||
parse_stats(counters, buf);
|
||||
}
|
||||
|
||||
/* update the stats counter for this compile */
|
||||
static void stats_update_size(enum stats stat, size_t size, size_t numfiles)
|
||||
{
|
||||
int fd;
|
||||
unsigned counters[STATS_END];
|
||||
int need_cleanup = 0;
|
||||
|
||||
if (getenv("CCACHE_NOSTATS")) return;
|
||||
|
||||
if (!stats_file) {
|
||||
if (!cache_dir) return;
|
||||
x_asprintf(&stats_file, "%s/stats", cache_dir);
|
||||
}
|
||||
|
||||
/* open safely to try to prevent symlink races */
|
||||
fd = safe_open(stats_file);
|
||||
|
||||
/* still can't get it? don't bother ... */
|
||||
if (fd == -1) return;
|
||||
|
||||
memset(counters, 0, sizeof(counters));
|
||||
|
||||
if (lock_fd(fd) != 0) {
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
/* read in the old stats */
|
||||
stats_read_fd(fd, counters);
|
||||
|
||||
/* update them */
|
||||
counters[stat]++;
|
||||
|
||||
/* on a cache miss we up the file count and size */
|
||||
if (stat == STATS_TOCACHE) {
|
||||
counters[STATS_NUMFILES] += numfiles;
|
||||
counters[STATS_TOTALSIZE] += size;
|
||||
}
|
||||
|
||||
/* and write them out */
|
||||
write_stats(fd, counters);
|
||||
close(fd);
|
||||
|
||||
/* we might need to cleanup if the cache has now got too big */
|
||||
if (counters[STATS_MAXFILES] != 0 &&
|
||||
counters[STATS_NUMFILES] > counters[STATS_MAXFILES]) {
|
||||
need_cleanup = 1;
|
||||
}
|
||||
if (counters[STATS_MAXSIZE] != 0 &&
|
||||
counters[STATS_TOTALSIZE] > counters[STATS_MAXSIZE]) {
|
||||
need_cleanup = 1;
|
||||
}
|
||||
|
||||
if (need_cleanup) {
|
||||
char *p = dirname(stats_file);
|
||||
cleanup_dir(p, counters[STATS_MAXFILES], counters[STATS_MAXSIZE],
|
||||
numfiles);
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
/* record a cache miss */
|
||||
void stats_tocache(size_t size, size_t numfiles)
|
||||
{
|
||||
/* convert size to kilobytes */
|
||||
size = size / 1024;
|
||||
|
||||
stats_update_size(STATS_TOCACHE, size, numfiles);
|
||||
}
|
||||
|
||||
/* update a normal stat */
|
||||
void stats_update(enum stats stat)
|
||||
{
|
||||
stats_update_size(stat, 0, 0);
|
||||
}
|
||||
|
||||
/* read in the stats from one dir and add to the counters */
|
||||
void stats_read(const char *stats_file, unsigned counters[STATS_END])
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open(stats_file, O_RDONLY|O_BINARY);
|
||||
if (fd == -1) {
|
||||
stats_default(counters);
|
||||
return;
|
||||
}
|
||||
lock_fd(fd);
|
||||
stats_read_fd(fd, counters);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* sum and display the total stats for all cache dirs */
|
||||
void stats_summary(void)
|
||||
{
|
||||
int dir, i;
|
||||
unsigned counters[STATS_END];
|
||||
|
||||
memset(counters, 0, sizeof(counters));
|
||||
|
||||
/* add up the stats in each directory */
|
||||
for (dir=-1;dir<=0xF;dir++) {
|
||||
char *fname;
|
||||
|
||||
if (dir == -1) {
|
||||
x_asprintf(&fname, "%s/stats", cache_dir);
|
||||
} else {
|
||||
x_asprintf(&fname, "%s/%1x/stats", cache_dir, dir);
|
||||
}
|
||||
|
||||
stats_read(fname, counters);
|
||||
free(fname);
|
||||
|
||||
/* oh what a nasty hack ... */
|
||||
if (dir == -1) {
|
||||
counters[STATS_MAXSIZE] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
printf("cache directory %s\n", cache_dir);
|
||||
|
||||
/* and display them */
|
||||
for (i=0;stats_info[i].message;i++) {
|
||||
enum stats stat = stats_info[i].stat;
|
||||
|
||||
if (counters[stat] == 0 &&
|
||||
!(stats_info[i].flags & FLAG_ALWAYS)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("%s ", stats_info[i].message);
|
||||
if (stats_info[i].fn) {
|
||||
stats_info[i].fn(counters[stat]);
|
||||
printf("\n");
|
||||
} else {
|
||||
printf("%8u\n", counters[stat]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* zero all the stats structures */
|
||||
void stats_zero(void)
|
||||
{
|
||||
int dir, fd;
|
||||
unsigned i;
|
||||
char *fname;
|
||||
unsigned counters[STATS_END];
|
||||
|
||||
x_asprintf(&fname, "%s/stats", cache_dir);
|
||||
unlink(fname);
|
||||
free(fname);
|
||||
|
||||
for (dir=0;dir<=0xF;dir++) {
|
||||
x_asprintf(&fname, "%s/%1x/stats", cache_dir, dir);
|
||||
fd = safe_open(fname);
|
||||
if (fd == -1) {
|
||||
free(fname);
|
||||
continue;
|
||||
}
|
||||
memset(counters, 0, sizeof(counters));
|
||||
lock_fd(fd);
|
||||
stats_read_fd(fd, counters);
|
||||
for (i=0;stats_info[i].message;i++) {
|
||||
if (!(stats_info[i].flags & FLAG_NOZERO)) {
|
||||
counters[stats_info[i].stat] = 0;
|
||||
}
|
||||
}
|
||||
write_stats(fd, counters);
|
||||
close(fd);
|
||||
free(fname);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* set the per directory limits */
|
||||
int stats_set_limits(long maxfiles, long maxsize)
|
||||
{
|
||||
int dir;
|
||||
unsigned counters[STATS_END];
|
||||
|
||||
if (maxfiles != -1) {
|
||||
maxfiles /= 16;
|
||||
}
|
||||
if (maxsize != -1) {
|
||||
maxsize /= 16;
|
||||
}
|
||||
|
||||
if (create_dir(cache_dir) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* set the limits in each directory */
|
||||
for (dir=0;dir<=0xF;dir++) {
|
||||
char *fname, *cdir;
|
||||
int fd;
|
||||
|
||||
x_asprintf(&cdir, "%s/%1x", cache_dir, dir);
|
||||
if (create_dir(cdir) != 0) {
|
||||
return 1;
|
||||
}
|
||||
x_asprintf(&fname, "%s/stats", cdir);
|
||||
free(cdir);
|
||||
|
||||
memset(counters, 0, sizeof(counters));
|
||||
fd = safe_open(fname);
|
||||
if (fd != -1) {
|
||||
lock_fd(fd);
|
||||
stats_read_fd(fd, counters);
|
||||
if (maxfiles != -1) {
|
||||
counters[STATS_MAXFILES] = maxfiles;
|
||||
}
|
||||
if (maxsize != -1) {
|
||||
counters[STATS_MAXSIZE] = maxsize;
|
||||
}
|
||||
write_stats(fd, counters);
|
||||
close(fd);
|
||||
}
|
||||
free(fname);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set the per directory sizes */
|
||||
void stats_set_sizes(const char *dir, size_t num_files, size_t total_size)
|
||||
{
|
||||
int fd;
|
||||
unsigned counters[STATS_END];
|
||||
char *stats_file;
|
||||
|
||||
create_dir(dir);
|
||||
x_asprintf(&stats_file, "%s/stats", dir);
|
||||
|
||||
memset(counters, 0, sizeof(counters));
|
||||
|
||||
fd = safe_open(stats_file);
|
||||
if (fd != -1) {
|
||||
lock_fd(fd);
|
||||
stats_read_fd(fd, counters);
|
||||
counters[STATS_NUMFILES] = num_files;
|
||||
counters[STATS_TOTALSIZE] = total_size;
|
||||
write_stats(fd, counters);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
free(stats_file);
|
||||
}
|
|
@ -0,0 +1,491 @@
|
|||
#!/bin/sh
|
||||
|
||||
# a simple test suite for ccache
|
||||
# tridge@samba.org
|
||||
|
||||
if test -n "$CC"; then
|
||||
COMPILER="$CC"
|
||||
else
|
||||
COMPILER=cc
|
||||
fi
|
||||
|
||||
if test -n "$SWIG"; then
|
||||
SWIG="$SWIG"
|
||||
else
|
||||
SWIG=swig
|
||||
fi
|
||||
|
||||
# fix: Remove ccache from $PATH if it exists
|
||||
# as it will influence the unit tests
|
||||
PATH="`echo $PATH | \
|
||||
sed -e 's!:/usr\(/local\)*/lib\([0-9]\)*/ccache\(/\)*!!g'`"
|
||||
|
||||
if test -n "$CCACHE"; then
|
||||
CCACHE="$CCACHE"
|
||||
else
|
||||
CCACHE=../ccache-swig
|
||||
fi
|
||||
|
||||
TESTDIR=test.$$
|
||||
|
||||
test_failed() {
|
||||
reason="$1"
|
||||
echo $1
|
||||
$CCACHE -s
|
||||
cd ..
|
||||
rm -rf $TESTDIR
|
||||
echo TEST FAILED
|
||||
exit 1
|
||||
}
|
||||
|
||||
randcode() {
|
||||
outfile="$1"
|
||||
nlines=$2
|
||||
i=0;
|
||||
(
|
||||
while [ $i -lt $nlines ]; do
|
||||
echo "int foo$nlines$i(int x) { return x; }"
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
) >> "$outfile"
|
||||
}
|
||||
|
||||
genswigcode() {
|
||||
outfile="$1"
|
||||
nlines=$2
|
||||
i=0;
|
||||
(
|
||||
echo "%module swigtest$2;"
|
||||
while [ $i -lt $nlines ]; do
|
||||
echo "int foo$nlines$i(int x);"
|
||||
echo "struct Bar$nlines$i { int y; };"
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
) >> "$outfile"
|
||||
}
|
||||
|
||||
|
||||
getstat() {
|
||||
stat="$1"
|
||||
value=`$CCACHE -s | grep "$stat" | cut -c34-40`
|
||||
echo $value
|
||||
}
|
||||
|
||||
checkstat() {
|
||||
stat="$1"
|
||||
expected_value="$2"
|
||||
value=`getstat "$stat"`
|
||||
# echo "exp: $expected_value got: $value $testname"
|
||||
if [ "$expected_value" != "$value" ]; then
|
||||
test_failed "SUITE: $testsuite TEST: $testname - Expected $stat to be $expected_value got $value"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
basetests() {
|
||||
echo "starting testsuite $testsuite"
|
||||
rm -rf "$CCACHE_DIR"
|
||||
checkstat 'cache hit' 0
|
||||
checkstat 'cache miss' 0
|
||||
|
||||
j=1
|
||||
rm -f *.c
|
||||
while [ $j -lt 32 ]; do
|
||||
randcode test$j.c $j
|
||||
j=`expr $j + 1`
|
||||
done
|
||||
|
||||
testname="BASIC"
|
||||
$CCACHE_COMPILE -c test1.c
|
||||
checkstat 'cache hit' 0
|
||||
checkstat 'cache miss' 1
|
||||
|
||||
testname="BASIC2"
|
||||
$CCACHE_COMPILE -c test1.c
|
||||
checkstat 'cache hit' 1
|
||||
checkstat 'cache miss' 1
|
||||
|
||||
testname="debug"
|
||||
$CCACHE_COMPILE -c test1.c -g
|
||||
checkstat 'cache hit' 1
|
||||
checkstat 'cache miss' 2
|
||||
|
||||
testname="debug2"
|
||||
$CCACHE_COMPILE -c test1.c -g
|
||||
checkstat 'cache hit' 2
|
||||
checkstat 'cache miss' 2
|
||||
|
||||
testname="output"
|
||||
$CCACHE_COMPILE -c test1.c -o foo.o
|
||||
checkstat 'cache hit' 3
|
||||
checkstat 'cache miss' 2
|
||||
|
||||
testname="link"
|
||||
$CCACHE_COMPILE test1.c -o test 2> /dev/null
|
||||
checkstat 'called for link' 1
|
||||
|
||||
testname="multiple"
|
||||
$CCACHE_COMPILE -c test1.c test2.c
|
||||
checkstat 'multiple source files' 1
|
||||
|
||||
testname="find"
|
||||
$CCACHE blahblah -c test1.c 2> /dev/null
|
||||
checkstat "couldn't find the compiler" 1
|
||||
|
||||
testname="bad"
|
||||
$CCACHE_COMPILE -c test1.c -I 2> /dev/null
|
||||
checkstat 'bad compiler arguments' 1
|
||||
|
||||
testname="c/c++"
|
||||
ln -f test1.c test1.ccc
|
||||
$CCACHE_COMPILE -c test1.ccc 2> /dev/null
|
||||
checkstat 'not a C/C++ file' 1
|
||||
|
||||
testname="unsupported"
|
||||
$CCACHE_COMPILE -M foo -c test1.c > /dev/null 2>&1
|
||||
checkstat 'unsupported compiler option' 1
|
||||
|
||||
testname="stdout"
|
||||
$CCACHE echo foo -c test1.c > /dev/null
|
||||
checkstat 'compiler produced stdout' 1
|
||||
|
||||
testname="non-regular"
|
||||
mkdir testd
|
||||
$CCACHE_COMPILE -o testd -c test1.c > /dev/null 2>&1
|
||||
rm -rf testd
|
||||
checkstat 'output to a non-regular file' 1
|
||||
|
||||
testname="no-input"
|
||||
$CCACHE_COMPILE -c -O2 2> /dev/null
|
||||
checkstat 'no input file' 1
|
||||
|
||||
|
||||
testname="CCACHE_DISABLE"
|
||||
CCACHE_DISABLE=1 $CCACHE_COMPILE -c test1.c 2> /dev/null
|
||||
checkstat 'cache hit' 3
|
||||
$CCACHE_COMPILE -c test1.c
|
||||
checkstat 'cache hit' 4
|
||||
|
||||
testname="CCACHE_CPP2"
|
||||
CCACHE_CPP2=1 $CCACHE_COMPILE -c test1.c -O -O
|
||||
checkstat 'cache hit' 4
|
||||
checkstat 'cache miss' 3
|
||||
|
||||
CCACHE_CPP2=1 $CCACHE_COMPILE -c test1.c -O -O
|
||||
checkstat 'cache hit' 5
|
||||
checkstat 'cache miss' 3
|
||||
|
||||
testname="CCACHE_NOSTATS"
|
||||
CCACHE_NOSTATS=1 $CCACHE_COMPILE -c test1.c -O -O
|
||||
checkstat 'cache hit' 5
|
||||
checkstat 'cache miss' 3
|
||||
|
||||
testname="CCACHE_RECACHE"
|
||||
CCACHE_RECACHE=1 $CCACHE_COMPILE -c test1.c -O -O
|
||||
checkstat 'cache hit' 5
|
||||
checkstat 'cache miss' 4
|
||||
|
||||
# strictly speaking should be 6 - RECACHE causes a double counting!
|
||||
checkstat 'files in cache' 8
|
||||
$CCACHE -c > /dev/null
|
||||
checkstat 'files in cache' 6
|
||||
|
||||
|
||||
testname="CCACHE_HASHDIR"
|
||||
CCACHE_HASHDIR=1 $CCACHE_COMPILE -c test1.c -O -O
|
||||
checkstat 'cache hit' 5
|
||||
checkstat 'cache miss' 5
|
||||
|
||||
CCACHE_HASHDIR=1 $CCACHE_COMPILE -c test1.c -O -O
|
||||
checkstat 'cache hit' 6
|
||||
checkstat 'cache miss' 5
|
||||
|
||||
checkstat 'files in cache' 8
|
||||
|
||||
testname="comments"
|
||||
echo '/* a silly comment */' > test1-comment.c
|
||||
cat test1.c >> test1-comment.c
|
||||
$CCACHE_COMPILE -c test1-comment.c
|
||||
rm -f test1-comment*
|
||||
checkstat 'cache hit' 6
|
||||
checkstat 'cache miss' 6
|
||||
|
||||
testname="CCACHE_UNIFY"
|
||||
CCACHE_UNIFY=1 $CCACHE_COMPILE -c test1.c
|
||||
checkstat 'cache hit' 6
|
||||
checkstat 'cache miss' 7
|
||||
mv test1.c test1-saved.c
|
||||
echo '/* another comment */' > test1.c
|
||||
cat test1-saved.c >> test1.c
|
||||
CCACHE_UNIFY=1 $CCACHE_COMPILE -c test1.c
|
||||
mv test1-saved.c test1.c
|
||||
checkstat 'cache hit' 7
|
||||
checkstat 'cache miss' 7
|
||||
|
||||
testname="cache-size"
|
||||
for f in *.c; do
|
||||
$CCACHE_COMPILE -c $f
|
||||
done
|
||||
checkstat 'cache hit' 8
|
||||
checkstat 'cache miss' 37
|
||||
checkstat 'files in cache' 72
|
||||
$CCACHE -F 48 -c > /dev/null
|
||||
if [ `getstat 'files in cache'` -gt 48 ]; then
|
||||
test_failed '-F test failed'
|
||||
fi
|
||||
|
||||
testname="cpp call"
|
||||
$CCACHE_COMPILE -c test1.c -E > test1.i
|
||||
checkstat 'cache hit' 8
|
||||
checkstat 'cache miss' 37
|
||||
|
||||
testname="direct .i compile"
|
||||
$CCACHE_COMPILE -c test1.c
|
||||
checkstat 'cache hit' 8
|
||||
checkstat 'cache miss' 38
|
||||
|
||||
$CCACHE_COMPILE -c test1.i
|
||||
checkstat 'cache hit' 9
|
||||
checkstat 'cache miss' 38
|
||||
|
||||
$CCACHE_COMPILE -c test1.i
|
||||
checkstat 'cache hit' 10
|
||||
checkstat 'cache miss' 38
|
||||
|
||||
# removed these tests as some compilers (including newer versions of gcc)
|
||||
# determine which language to use based on .ii/.i extension, and C++ may
|
||||
# not be installed
|
||||
# testname="direct .ii file"
|
||||
# mv test1.i test1.ii
|
||||
# $CCACHE_COMPILE -c test1.ii
|
||||
# checkstat 'cache hit' 10
|
||||
# checkstat 'cache miss' 39
|
||||
|
||||
# $CCACHE_COMPILE -c test1.ii
|
||||
# checkstat 'cache hit' 11
|
||||
# checkstat 'cache miss' 39
|
||||
|
||||
testname="stripc" # This test might not be portable
|
||||
CCACHE_STRIPC=1 $CCACHE_COMPILE -c test1.c
|
||||
checkstat 'cache hit' 10
|
||||
checkstat 'cache miss' 39
|
||||
|
||||
CCACHE_STRIPC=1 $CCACHE_COMPILE -c test1.c
|
||||
checkstat 'cache hit' 11
|
||||
checkstat 'cache miss' 39
|
||||
|
||||
testname="zero-stats"
|
||||
$CCACHE -z > /dev/null
|
||||
checkstat 'cache hit' 0
|
||||
checkstat 'cache miss' 0
|
||||
|
||||
testname="clear"
|
||||
$CCACHE -C > /dev/null
|
||||
checkstat 'files in cache' 0
|
||||
|
||||
|
||||
rm -f test1.c
|
||||
}
|
||||
|
||||
swigtests() {
|
||||
echo "starting swig testsuite $testsuite"
|
||||
rm -rf "$CCACHE_DIR"
|
||||
checkstat 'cache hit' 0
|
||||
checkstat 'cache miss' 0
|
||||
|
||||
j=1
|
||||
rm -f *.i
|
||||
genswigcode testswig1.i 1
|
||||
|
||||
testname="BASIC"
|
||||
$CCACHE_COMPILE -java testswig1.i
|
||||
checkstat 'cache hit' 0
|
||||
checkstat 'cache miss' 1
|
||||
|
||||
checkstat 'files in cache' 6
|
||||
|
||||
testname="BASIC2"
|
||||
$CCACHE_COMPILE -java testswig1.i
|
||||
checkstat 'cache hit' 1
|
||||
checkstat 'cache miss' 1
|
||||
|
||||
testname="output"
|
||||
$CCACHE_COMPILE -java testswig1.i -o foo_wrap.c
|
||||
checkstat 'cache hit' 1
|
||||
checkstat 'cache miss' 2
|
||||
|
||||
testname="bad"
|
||||
$CCACHE_COMPILE -java testswig1.i -I 2> /dev/null
|
||||
checkstat 'bad compiler arguments' 1
|
||||
|
||||
testname="stdout"
|
||||
$CCACHE_COMPILE -v -java testswig1.i > /dev/null
|
||||
checkstat 'compiler produced stdout' 1
|
||||
|
||||
testname="non-regular"
|
||||
mkdir testd
|
||||
$CCACHE_COMPILE -o testd -java testswig1.i > /dev/null 2>&1
|
||||
rm -rf testd
|
||||
checkstat 'output to a non-regular file' 1
|
||||
|
||||
testname="no-input"
|
||||
$CCACHE_COMPILE -java 2> /dev/null
|
||||
checkstat 'no input file' 1
|
||||
|
||||
|
||||
testname="CCACHE_DISABLE"
|
||||
CCACHE_DISABLE=1 $CCACHE_COMPILE -java testswig1.i 2> /dev/null
|
||||
checkstat 'cache hit' 1
|
||||
$CCACHE_COMPILE -java testswig1.i
|
||||
checkstat 'cache hit' 2
|
||||
|
||||
testname="CCACHE_CPP2"
|
||||
CCACHE_CPP2=1 $CCACHE_COMPILE -java -O -O testswig1.i
|
||||
checkstat 'cache hit' 2
|
||||
checkstat 'cache miss' 3
|
||||
|
||||
CCACHE_CPP2=1 $CCACHE_COMPILE -java -O -O testswig1.i
|
||||
checkstat 'cache hit' 3
|
||||
checkstat 'cache miss' 3
|
||||
|
||||
testname="CCACHE_NOSTATS"
|
||||
CCACHE_NOSTATS=1 $CCACHE_COMPILE -java -O -O testswig1.i
|
||||
checkstat 'cache hit' 3
|
||||
checkstat 'cache miss' 3
|
||||
|
||||
testname="CCACHE_RECACHE"
|
||||
CCACHE_RECACHE=1 $CCACHE_COMPILE -java -O -O testswig1.i
|
||||
checkstat 'cache hit' 3
|
||||
checkstat 'cache miss' 4
|
||||
|
||||
# strictly speaking should be 3x6=18 instead of 4x6=24 - RECACHE causes a double counting!
|
||||
checkstat 'files in cache' 24
|
||||
$CCACHE -c > /dev/null
|
||||
checkstat 'files in cache' 18
|
||||
|
||||
|
||||
testname="CCACHE_HASHDIR"
|
||||
CCACHE_HASHDIR=1 $CCACHE_COMPILE -java -O -O testswig1.i
|
||||
checkstat 'cache hit' 3
|
||||
checkstat 'cache miss' 5
|
||||
|
||||
CCACHE_HASHDIR=1 $CCACHE_COMPILE -java -O -O testswig1.i
|
||||
checkstat 'cache hit' 4
|
||||
checkstat 'cache miss' 5
|
||||
|
||||
checkstat 'files in cache' 24
|
||||
|
||||
testname="cpp call"
|
||||
$CCACHE_COMPILE -java -E testswig1.i > testswig1-preproc.i
|
||||
checkstat 'cache hit' 4
|
||||
checkstat 'cache miss' 5
|
||||
|
||||
testname="direct .i compile"
|
||||
$CCACHE_COMPILE -java testswig1.i
|
||||
checkstat 'cache hit' 5
|
||||
checkstat 'cache miss' 5
|
||||
|
||||
# No cache hit due to different input file name, -nopreprocess should not be given twice to SWIG
|
||||
$CCACHE_COMPILE -java -nopreprocess testswig1-preproc.i
|
||||
checkstat 'cache hit' 5
|
||||
checkstat 'cache miss' 6
|
||||
|
||||
$CCACHE_COMPILE -java -nopreprocess testswig1-preproc.i
|
||||
checkstat 'cache hit' 6
|
||||
checkstat 'cache miss' 6
|
||||
|
||||
testname="stripc"
|
||||
CCACHE_STRIPC=1 $CCACHE_COMPILE -java -O -O testswig1.i
|
||||
checkstat 'cache hit' 7
|
||||
checkstat 'cache miss' 6
|
||||
|
||||
CCACHE_STRIPC=1 $CCACHE_COMPILE -java -O -O -O testswig1.i
|
||||
checkstat 'cache hit' 7
|
||||
checkstat 'cache miss' 7
|
||||
|
||||
rm -f testswig1-preproc.i
|
||||
rm -f testswig1.i
|
||||
}
|
||||
|
||||
######
|
||||
# main program
|
||||
rm -rf $TESTDIR
|
||||
mkdir $TESTDIR
|
||||
if test -n "$CCACHE_PROG"; then
|
||||
ln -s $CCACHE $TESTDIR/$CCACHE_PROG
|
||||
CCACHE=./$CCACHE_PROG
|
||||
fi
|
||||
cd $TESTDIR || exit 1
|
||||
|
||||
unset CCACHE_DIR
|
||||
unset CCACHE_TEMPDIR
|
||||
unset CCACHE_LOGFILE
|
||||
unset CCACHE_VERBOSE
|
||||
unset CCACHE_PATH
|
||||
unset CCACHE_CC
|
||||
unset CCACHE_PREFIX
|
||||
unset CCACHE_DISABLE
|
||||
unset CCACHE_READONLY
|
||||
unset CCACHE_CPP2
|
||||
unset CCACHE_NOCOMPRESS
|
||||
unset CCACHE_NOSTATS
|
||||
unset CCACHE_NLEVELS
|
||||
unset CCACHE_HARDLINK
|
||||
unset CCACHE_RECACHE
|
||||
unset CCACHE_UMASK
|
||||
unset CCACHE_HASHDIR
|
||||
unset CCACHE_UNIFY
|
||||
unset CCACHE_EXTENSION
|
||||
unset CCACHE_STRIPC
|
||||
unset CCACHE_SWIG
|
||||
|
||||
CCACHE_DIR="ccache dir" # with space in directory name (like Windows default)
|
||||
mkdir "$CCACHE_DIR"
|
||||
export CCACHE_DIR
|
||||
|
||||
testsuite="base"
|
||||
CCACHE_COMPILE="$CCACHE $COMPILER"
|
||||
basetests
|
||||
CCACHE_COMPILE="$CCACHE $SWIG"
|
||||
swigtests
|
||||
|
||||
if test -z "$NOSOFTLINKSTEST"; then
|
||||
testsuite="link"
|
||||
compilername=`basename $COMPILER`
|
||||
ln -s $CCACHE ./$compilername
|
||||
CCACHE_COMPILE="./$compilername"
|
||||
basetests
|
||||
rm "./$compilername"
|
||||
compilername=`basename $SWIG`
|
||||
ln -s $CCACHE ./$compilername
|
||||
CCACHE_COMPILE="./$compilername"
|
||||
swigtests
|
||||
rm "./$compilername"
|
||||
else
|
||||
echo "skipping testsuite link"
|
||||
fi
|
||||
|
||||
testsuite="hardlink"
|
||||
CCACHE_COMPILE="env CCACHE_NOCOMPRESS=1 CCACHE_HARDLINK=1 $CCACHE $COMPILER"
|
||||
basetests
|
||||
CCACHE_COMPILE="env CCACHE_NOCOMPRESS=1 CCACHE_HARDLINK=1 $CCACHE $SWIG"
|
||||
swigtests
|
||||
|
||||
testsuite="cpp2"
|
||||
CCACHE_COMPILE="env CCACHE_CPP2=1 $CCACHE $COMPILER"
|
||||
basetests
|
||||
CCACHE_COMPILE="env CCACHE_CPP2=1 $CCACHE $SWIG"
|
||||
swigtests
|
||||
|
||||
testsuite="nlevels4"
|
||||
CCACHE_COMPILE="env CCACHE_NLEVELS=4 $CCACHE $COMPILER"
|
||||
basetests
|
||||
|
||||
testsuite="nlevels1"
|
||||
CCACHE_COMPILE="env CCACHE_NLEVELS=1 $CCACHE $COMPILER"
|
||||
basetests
|
||||
|
||||
cd ..
|
||||
rm -rf $TESTDIR
|
||||
echo test done - OK
|
||||
exit 0
|
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
Copyright (C) Andrew Tridgell 2002
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/*
|
||||
C/C++ unifier
|
||||
|
||||
the idea is that changes that don't affect the resulting C code
|
||||
should not change the hash. This is achieved by folding white-space
|
||||
and other non-semantic fluff in the input into a single unified format.
|
||||
|
||||
This unifier was design to match the output of the unifier in
|
||||
compilercache, which is flex based. The major difference is that
|
||||
this unifier is much faster (about 2x) and more forgiving of
|
||||
syntactic errors. Continuing on syntactic errors is important to
|
||||
cope with C/C++ extensions in the local compiler (for example,
|
||||
inline assembly systems).
|
||||
*/
|
||||
|
||||
#include "ccache.h"
|
||||
|
||||
static char *s_tokens[] = {
|
||||
"...", ">>=", "<<=", "+=", "-=", "*=", "/=", "%=", "&=", "^=",
|
||||
"|=", ">>", "<<", "++", "--", "->", "&&", "||", "<=", ">=",
|
||||
"==", "!=", ";", "{", "<%", "}", "%>", ",", ":", "=",
|
||||
"(", ")", "[", "<:", "]", ":>", ".", "&", "!", "~",
|
||||
"-", "+", "*", "/", "%", "<", ">", "^", "|", "?",
|
||||
0
|
||||
};
|
||||
|
||||
#define C_ALPHA 1
|
||||
#define C_SPACE 2
|
||||
#define C_TOKEN 4
|
||||
#define C_QUOTE 8
|
||||
#define C_DIGIT 16
|
||||
#define C_HEX 32
|
||||
#define C_FLOAT 64
|
||||
#define C_SIGN 128
|
||||
|
||||
static struct {
|
||||
unsigned char type;
|
||||
unsigned char num_toks;
|
||||
char *toks[7];
|
||||
} tokens[256];
|
||||
|
||||
/* build up the table used by the unifier */
|
||||
static void build_table(void)
|
||||
{
|
||||
unsigned char c;
|
||||
int i;
|
||||
static int done;
|
||||
|
||||
if (done) return;
|
||||
done = 1;
|
||||
|
||||
memset(tokens, 0, sizeof(tokens));
|
||||
for (c=0;c<128;c++) {
|
||||
if (isalpha(c) || c == '_') tokens[c].type |= C_ALPHA;
|
||||
if (isdigit(c)) tokens[c].type |= C_DIGIT;
|
||||
if (isspace(c)) tokens[c].type |= C_SPACE;
|
||||
if (isxdigit(c)) tokens[c].type |= C_HEX;
|
||||
}
|
||||
tokens['\''].type |= C_QUOTE;
|
||||
tokens['"'].type |= C_QUOTE;
|
||||
tokens['l'].type |= C_FLOAT;
|
||||
tokens['L'].type |= C_FLOAT;
|
||||
tokens['f'].type |= C_FLOAT;
|
||||
tokens['F'].type |= C_FLOAT;
|
||||
tokens['U'].type |= C_FLOAT;
|
||||
tokens['u'].type |= C_FLOAT;
|
||||
|
||||
tokens['-'].type |= C_SIGN;
|
||||
tokens['+'].type |= C_SIGN;
|
||||
|
||||
for (i=0;s_tokens[i];i++) {
|
||||
c = s_tokens[i][0];
|
||||
tokens[c].type |= C_TOKEN;
|
||||
tokens[c].toks[tokens[c].num_toks] = s_tokens[i];
|
||||
tokens[c].num_toks++;
|
||||
}
|
||||
}
|
||||
|
||||
/* buffer up characters before hashing them */
|
||||
static void pushchar(unsigned char c)
|
||||
{
|
||||
static unsigned char buf[64];
|
||||
static int len;
|
||||
|
||||
if (c == 0) {
|
||||
if (len > 0) {
|
||||
hash_buffer((char *)buf, len);
|
||||
len = 0;
|
||||
}
|
||||
hash_buffer(NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
buf[len++] = c;
|
||||
if (len == 64) {
|
||||
hash_buffer((char *)buf, len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* hash some C/C++ code after unifying */
|
||||
static void unify(unsigned char *p, size_t size)
|
||||
{
|
||||
size_t ofs;
|
||||
unsigned char q;
|
||||
int i;
|
||||
|
||||
build_table();
|
||||
|
||||
for (ofs=0; ofs<size;) {
|
||||
if (p[ofs] == '#') {
|
||||
if ((size-ofs) > 2 && p[ofs+1] == ' ' && isdigit(p[ofs+2])) {
|
||||
do {
|
||||
ofs++;
|
||||
} while (ofs < size && p[ofs] != '\n');
|
||||
ofs++;
|
||||
} else {
|
||||
do {
|
||||
pushchar(p[ofs]);
|
||||
ofs++;
|
||||
} while (ofs < size && p[ofs] != '\n');
|
||||
pushchar('\n');
|
||||
ofs++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tokens[p[ofs]].type & C_ALPHA) {
|
||||
do {
|
||||
pushchar(p[ofs]);
|
||||
ofs++;
|
||||
} while (ofs < size &&
|
||||
(tokens[p[ofs]].type & (C_ALPHA|C_DIGIT)));
|
||||
pushchar('\n');
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tokens[p[ofs]].type & C_DIGIT) {
|
||||
do {
|
||||
pushchar(p[ofs]);
|
||||
ofs++;
|
||||
} while (ofs < size &&
|
||||
((tokens[p[ofs]].type & C_DIGIT) || p[ofs] == '.'));
|
||||
if (ofs < size && (p[ofs] == 'x' || p[ofs] == 'X')) {
|
||||
do {
|
||||
pushchar(p[ofs]);
|
||||
ofs++;
|
||||
} while (ofs < size && (tokens[p[ofs]].type & C_HEX));
|
||||
}
|
||||
if (ofs < size && (p[ofs] == 'E' || p[ofs] == 'e')) {
|
||||
pushchar(p[ofs]);
|
||||
ofs++;
|
||||
while (ofs < size &&
|
||||
(tokens[p[ofs]].type & (C_DIGIT|C_SIGN))) {
|
||||
pushchar(p[ofs]);
|
||||
ofs++;
|
||||
}
|
||||
}
|
||||
while (ofs < size && (tokens[p[ofs]].type & C_FLOAT)) {
|
||||
pushchar(p[ofs]);
|
||||
ofs++;
|
||||
}
|
||||
pushchar('\n');
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tokens[p[ofs]].type & C_SPACE) {
|
||||
do {
|
||||
ofs++;
|
||||
} while (ofs < size && (tokens[p[ofs]].type & C_SPACE));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tokens[p[ofs]].type & C_QUOTE) {
|
||||
q = p[ofs];
|
||||
pushchar(p[ofs]);
|
||||
do {
|
||||
ofs++;
|
||||
while (ofs < size-1 && p[ofs] == '\\') {
|
||||
pushchar(p[ofs]);
|
||||
pushchar(p[ofs+1]);
|
||||
ofs+=2;
|
||||
}
|
||||
pushchar(p[ofs]);
|
||||
} while (ofs < size && p[ofs] != q);
|
||||
pushchar('\n');
|
||||
ofs++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tokens[p[ofs]].type & C_TOKEN) {
|
||||
q = p[ofs];
|
||||
for (i=0;i<tokens[q].num_toks;i++) {
|
||||
unsigned char *s = (unsigned char *)tokens[q].toks[i];
|
||||
int len = strlen((char *)s);
|
||||
if (size >= ofs+len && memcmp(&p[ofs], s, len) == 0) {
|
||||
int j;
|
||||
for (j=0;s[j];j++) {
|
||||
pushchar(s[j]);
|
||||
ofs++;
|
||||
}
|
||||
pushchar('\n');
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < tokens[q].num_toks) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
pushchar(p[ofs]);
|
||||
pushchar('\n');
|
||||
ofs++;
|
||||
}
|
||||
pushchar(0);
|
||||
}
|
||||
|
||||
|
||||
/* hash a file that consists of preprocessor output, but remove any line
|
||||
number information from the hash
|
||||
*/
|
||||
int unify_hash(const char *fname)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
HANDLE file;
|
||||
HANDLE section;
|
||||
DWORD filesize_low;
|
||||
char *map;
|
||||
int ret = -1;
|
||||
|
||||
file = CreateFileA(fname, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, 0, NULL);
|
||||
if (file != INVALID_HANDLE_VALUE) {
|
||||
filesize_low = GetFileSize(file, NULL);
|
||||
if (!(filesize_low == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)) {
|
||||
section = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
CloseHandle(file);
|
||||
if (section != NULL) {
|
||||
map = MapViewOfFile(section, FILE_MAP_READ, 0, 0, 0);
|
||||
CloseHandle(section);
|
||||
if (map != NULL)
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == -1) {
|
||||
cc_log("Failed to open preprocessor output %s\n", fname);
|
||||
stats_update(STATS_PREPROCESSOR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* pass it through the unifier */
|
||||
unify((unsigned char *)map, filesize_low);
|
||||
|
||||
UnmapViewOfFile(map);
|
||||
|
||||
return 0;
|
||||
#else
|
||||
int fd;
|
||||
struct stat st;
|
||||
char *map;
|
||||
|
||||
fd = open(fname, O_RDONLY|O_BINARY);
|
||||
if (fd == -1 || fstat(fd, &st) != 0) {
|
||||
cc_log("Failed to open preprocessor output %s\n", fname);
|
||||
if (fd != -1) close(fd);
|
||||
stats_update(STATS_PREPROCESSOR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we use mmap() to make it easy to handle arbitrarily long
|
||||
lines in preprocessor output. I have seen lines of over
|
||||
100k in length, so this is well worth it */
|
||||
map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
close(fd);
|
||||
if (map == (char *)-1) {
|
||||
cc_log("Failed to mmap %s\n", fname);
|
||||
stats_update(STATS_PREPROCESSOR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* pass it through the unifier */
|
||||
unify((unsigned char *)map, st.st_size);
|
||||
|
||||
munmap(map, st.st_size);
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,889 @@
|
|||
/*
|
||||
Copyright (C) Andrew Tridgell 2002
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "ccache.h"
|
||||
|
||||
static FILE *logfile;
|
||||
|
||||
/* log a message to the CCACHE_LOGFILE location */
|
||||
void cc_log(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
extern char *cache_logfile;
|
||||
|
||||
if (!cache_logfile) return;
|
||||
|
||||
if (!logfile) logfile = fopen(cache_logfile, "a");
|
||||
if (!logfile) return;
|
||||
|
||||
va_start(ap, format);
|
||||
vfprintf(logfile, format, ap);
|
||||
va_end(ap);
|
||||
fflush(logfile);
|
||||
}
|
||||
|
||||
/* something went badly wrong! */
|
||||
void fatal(const char *msg)
|
||||
{
|
||||
cc_log("FATAL: %s\n", msg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int safe_rename(const char* oldpath, const char* newpath)
|
||||
{
|
||||
/* safe_rename is for creating entries in the cache.
|
||||
|
||||
Works like rename(), but it never overwrites an existing
|
||||
cache entry. This avoids corruption on NFS. */
|
||||
#ifndef _WIN32
|
||||
int status = link(oldpath, newpath);
|
||||
if( status == 0 || errno == EEXIST )
|
||||
#else
|
||||
int status = CreateHardLinkA(newpath, oldpath, NULL) ? 0 : -1;
|
||||
if( status == 0 || GetLastError() == ERROR_ALREADY_EXISTS )
|
||||
#endif
|
||||
{
|
||||
return unlink( oldpath );
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef ENABLE_ZLIB
|
||||
/* copy all data from one file descriptor to another */
|
||||
void copy_fd(int fd_in, int fd_out)
|
||||
{
|
||||
char buf[10240];
|
||||
int n;
|
||||
|
||||
while ((n = read(fd_in, buf, sizeof(buf))) > 0) {
|
||||
if (write(fd_out, buf, n) != n) {
|
||||
fatal("Failed to copy fd");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef HAVE_MKSTEMP
|
||||
/* cheap and nasty mkstemp replacement */
|
||||
int mkstemp(char *template)
|
||||
{
|
||||
mktemp(template);
|
||||
return open(template, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* move a file using rename */
|
||||
int move_file(const char *src, const char *dest) {
|
||||
return safe_rename(src, dest);
|
||||
}
|
||||
|
||||
/* copy a file - used when hard links don't work
|
||||
the copy is done via a temporary file and atomic rename
|
||||
*/
|
||||
static int copy_file(const char *src, const char *dest)
|
||||
{
|
||||
int fd1, fd2;
|
||||
char buf[10240];
|
||||
int n;
|
||||
char *tmp_name;
|
||||
mode_t mask;
|
||||
|
||||
x_asprintf(&tmp_name, "%s.XXXXXX", dest);
|
||||
|
||||
fd1 = open(src, O_RDONLY|O_BINARY);
|
||||
if (fd1 == -1) {
|
||||
free(tmp_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd2 = mkstemp(tmp_name);
|
||||
if (fd2 == -1) {
|
||||
close(fd1);
|
||||
free(tmp_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((n = read(fd1, buf, sizeof(buf))) > 0) {
|
||||
if (write(fd2, buf, n) != n) {
|
||||
close(fd2);
|
||||
close(fd1);
|
||||
unlink(tmp_name);
|
||||
free(tmp_name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd1);
|
||||
|
||||
/* get perms right on the tmp file */
|
||||
#ifndef _WIN32
|
||||
mask = umask(0);
|
||||
fchmod(fd2, 0666 & ~mask);
|
||||
umask(mask);
|
||||
#else
|
||||
(void)mask;
|
||||
#endif
|
||||
|
||||
/* the close can fail on NFS if out of space */
|
||||
if (close(fd2) == -1) {
|
||||
unlink(tmp_name);
|
||||
free(tmp_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
unlink(dest);
|
||||
|
||||
if (rename(tmp_name, dest) == -1) {
|
||||
unlink(tmp_name);
|
||||
free(tmp_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(tmp_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* copy a file to the cache */
|
||||
static int copy_file_to_cache(const char *src, const char *dest) {
|
||||
return copy_file(src, dest);
|
||||
}
|
||||
|
||||
/* copy a file from the cache */
|
||||
static int copy_file_from_cache(const char *src, const char *dest) {
|
||||
return copy_file(src, dest);
|
||||
}
|
||||
|
||||
#else /* ENABLE_ZLIB */
|
||||
|
||||
/* copy all data from one file descriptor to another
|
||||
possibly decompressing it
|
||||
*/
|
||||
void copy_fd(int fd_in, int fd_out) {
|
||||
char buf[10240];
|
||||
int n;
|
||||
gzFile gz_in;
|
||||
|
||||
gz_in = gzdopen(dup(fd_in), "rb");
|
||||
|
||||
if (!gz_in) {
|
||||
fatal("Failed to copy fd");
|
||||
}
|
||||
|
||||
while ((n = gzread(gz_in, buf, sizeof(buf))) > 0) {
|
||||
if (write(fd_out, buf, n) != n) {
|
||||
gzclose(gz_in);
|
||||
fatal("Failed to copy fd");
|
||||
}
|
||||
}
|
||||
gzclose(gz_in);
|
||||
}
|
||||
|
||||
static int _copy_file(const char *src, const char *dest, int mode) {
|
||||
int fd_in, fd_out;
|
||||
gzFile gz_in, gz_out = NULL;
|
||||
char buf[10240];
|
||||
int n, ret;
|
||||
char *tmp_name;
|
||||
mode_t mask;
|
||||
struct stat st;
|
||||
|
||||
x_asprintf(&tmp_name, "%s.XXXXXX", dest);
|
||||
|
||||
if (getenv("CCACHE_NOCOMPRESS")) {
|
||||
mode = COPY_UNCOMPRESSED;
|
||||
}
|
||||
|
||||
/* open source file */
|
||||
fd_in = open(src, O_RDONLY);
|
||||
if (fd_in == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gz_in = gzdopen(fd_in, "rb");
|
||||
if (!gz_in) {
|
||||
close(fd_in);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* open destination file */
|
||||
fd_out = mkstemp(tmp_name);
|
||||
if (fd_out == -1) {
|
||||
gzclose(gz_in);
|
||||
free(tmp_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mode == COPY_TO_CACHE) {
|
||||
/* The gzip file format occupies at least 20 bytes. So
|
||||
it will always occupy an entire filesystem block,
|
||||
even for empty files.
|
||||
Since most stderr files will be empty, we turn off
|
||||
compression in this case to save space.
|
||||
*/
|
||||
if (fstat(fd_in, &st) != 0) {
|
||||
gzclose(gz_in);
|
||||
close(fd_out);
|
||||
free(tmp_name);
|
||||
return -1;
|
||||
}
|
||||
if (file_size(&st) == 0) {
|
||||
mode = COPY_UNCOMPRESSED;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == COPY_TO_CACHE) {
|
||||
int dup_fd_out = dup(fd_out);
|
||||
gz_out = gzdopen(dup_fd_out, "wb");
|
||||
if (!gz_out) {
|
||||
gzclose(gz_in);
|
||||
close(dup_fd_out);
|
||||
close(fd_out);
|
||||
free(tmp_name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
while ((n = gzread(gz_in, buf, sizeof(buf))) > 0) {
|
||||
if (mode == COPY_TO_CACHE) {
|
||||
ret = gzwrite(gz_out, buf, n);
|
||||
} else {
|
||||
ret = write(fd_out, buf, n);
|
||||
}
|
||||
if (ret != n) {
|
||||
gzclose(gz_in);
|
||||
if (gz_out) {
|
||||
gzclose(gz_out);
|
||||
}
|
||||
close(fd_out);
|
||||
unlink(tmp_name);
|
||||
free(tmp_name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
gzclose(gz_in);
|
||||
if (gz_out) {
|
||||
gzclose(gz_out);
|
||||
}
|
||||
|
||||
/* get perms right on the tmp file */
|
||||
mask = umask(0);
|
||||
fchmod(fd_out, 0666 & ~mask);
|
||||
umask(mask);
|
||||
|
||||
/* the close can fail on NFS if out of space */
|
||||
if (close(fd_out) == -1) {
|
||||
unlink(tmp_name);
|
||||
free(tmp_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
unlink(dest);
|
||||
|
||||
if (rename(tmp_name, dest) == -1) {
|
||||
unlink(tmp_name);
|
||||
free(tmp_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(tmp_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* move a file to the cache, compressing it */
|
||||
int move_file(const char *src, const char *dest) {
|
||||
int ret;
|
||||
|
||||
ret = _copy_file(src, dest, COPY_TO_CACHE);
|
||||
if (ret != -1) unlink(src);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* copy a file to the cache, compressing it */
|
||||
static int copy_file_to_cache(const char *src, const char *dest) {
|
||||
return _copy_file(src, dest, COPY_TO_CACHE);
|
||||
}
|
||||
|
||||
/* copy a file from the cache, decompressing it */
|
||||
static int copy_file_from_cache(const char *src, const char *dest) {
|
||||
return _copy_file(src, dest, COPY_FROM_CACHE);
|
||||
}
|
||||
#endif /* ENABLE_ZLIB */
|
||||
|
||||
/* test if a file is zlib compressed */
|
||||
int test_if_compressed(const char *filename) {
|
||||
FILE *f;
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if (!f) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* test if file starts with 1F8B, which is zlib's
|
||||
* magic number */
|
||||
if ((fgetc(f) != 0x1f) || (fgetc(f) != 0x8b)) {
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* copy file to the cache with error checking taking into account compression and hard linking if desired */
|
||||
int commit_to_cache(const char *src, const char *dest, int hardlink)
|
||||
{
|
||||
int ret = -1;
|
||||
struct stat st;
|
||||
if (stat(src, &st) == 0) {
|
||||
unlink(dest);
|
||||
if (hardlink) {
|
||||
#ifdef _WIN32
|
||||
ret = CreateHardLinkA(dest, src, NULL) ? 0 : -1;
|
||||
#else
|
||||
ret = link(src, dest);
|
||||
#endif
|
||||
}
|
||||
if (ret == -1) {
|
||||
ret = copy_file_to_cache(src, dest);
|
||||
if (ret == -1) {
|
||||
cc_log("failed to commit %s -> %s (%s)\n", src, dest, strerror(errno));
|
||||
stats_update(STATS_ERROR);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cc_log("failed to put %s in the cache (%s)\n", src, strerror(errno));
|
||||
stats_update(STATS_ERROR);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* copy file out of the cache with error checking taking into account compression and hard linking if desired */
|
||||
int retrieve_from_cache(const char *src, const char *dest, int hardlink)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
x_utimes(src);
|
||||
|
||||
if (strcmp(dest, "/dev/null") == 0) {
|
||||
ret = 0;
|
||||
} else {
|
||||
unlink(dest);
|
||||
/* only make a hardlink if the cache file is uncompressed */
|
||||
if (hardlink && test_if_compressed(src) == 0) {
|
||||
#ifdef _WIN32
|
||||
ret = CreateHardLinkA(dest, src, NULL) ? 0 : -1;
|
||||
#else
|
||||
ret = link(src, dest);
|
||||
#endif
|
||||
} else {
|
||||
ret = copy_file_from_cache(src, dest);
|
||||
}
|
||||
}
|
||||
|
||||
/* the cached file might have been deleted by some external process */
|
||||
if (ret == -1 && errno == ENOENT) {
|
||||
cc_log("hashfile missing for %s\n", dest);
|
||||
stats_update(STATS_MISSING);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == -1) {
|
||||
ret = copy_file_from_cache(src, dest);
|
||||
if (ret == -1) {
|
||||
cc_log("failed to retrieve %s -> %s (%s)\n", src, dest, strerror(errno));
|
||||
stats_update(STATS_ERROR);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* make sure a directory exists */
|
||||
int create_dir(const char *dir)
|
||||
{
|
||||
struct stat st;
|
||||
if (stat(dir, &st) == 0) {
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
return 0;
|
||||
}
|
||||
errno = ENOTDIR;
|
||||
return 1;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
if (mkdir(dir) != 0 && errno != EEXIST) {
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
if (mkdir(dir, 0777) != 0 && errno != EEXIST) {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
char const CACHEDIR_TAG[] =
|
||||
"Signature: 8a477f597d28d172789f06886806bc55\n"
|
||||
"# This file is a cache directory tag created by ccache.\n"
|
||||
"# For information about cache directory tags, see:\n"
|
||||
"# http://www.brynosaurus.com/cachedir/\n";
|
||||
|
||||
int create_cachedirtag(const char *dir)
|
||||
{
|
||||
char *filename;
|
||||
struct stat st;
|
||||
FILE *f;
|
||||
x_asprintf(&filename, "%s/CACHEDIR.TAG", dir);
|
||||
if (stat(filename, &st) == 0) {
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
goto success;
|
||||
}
|
||||
errno = EEXIST;
|
||||
goto error;
|
||||
}
|
||||
f = fopen(filename, "w");
|
||||
if (!f) goto error;
|
||||
if (fwrite(CACHEDIR_TAG, sizeof(CACHEDIR_TAG)-1, 1, f) != 1) {
|
||||
fclose(f);
|
||||
goto error;
|
||||
}
|
||||
if (fclose(f)) goto error;
|
||||
success:
|
||||
free(filename);
|
||||
return 0;
|
||||
error:
|
||||
free(filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
this is like asprintf() but dies if the malloc fails
|
||||
note that we use vsnprintf in a rather poor way to make this more portable
|
||||
*/
|
||||
void x_asprintf(char **ptr, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
*ptr = NULL;
|
||||
va_start(ap, format);
|
||||
if (vasprintf(ptr, format, ap) == -1) {
|
||||
fatal("out of memory in x_asprintf");
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
if (!*ptr) fatal("out of memory in x_asprintf");
|
||||
}
|
||||
|
||||
/*
|
||||
this is like strdup() but dies if the malloc fails
|
||||
*/
|
||||
char *x_strdup(const char *s)
|
||||
{
|
||||
char *ret;
|
||||
ret = strdup(s);
|
||||
if (!ret) {
|
||||
fatal("out of memory in strdup\n");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
this is like malloc() but dies if the malloc fails
|
||||
*/
|
||||
void *x_malloc(size_t size)
|
||||
{
|
||||
void *ret;
|
||||
ret = malloc(size);
|
||||
if (!ret) {
|
||||
fatal("out of memory in malloc\n");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
this is like realloc() but dies if the malloc fails
|
||||
*/
|
||||
void *x_realloc(void *ptr, size_t size)
|
||||
{
|
||||
void *p2;
|
||||
#if 1
|
||||
/* Avoid invalid read in memcpy below */
|
||||
p2 = realloc(ptr, size);
|
||||
if (!p2) {
|
||||
fatal("out of memory in x_realloc");
|
||||
}
|
||||
#else
|
||||
if (!ptr) return x_malloc(size);
|
||||
p2 = malloc(size);
|
||||
if (!p2) {
|
||||
fatal("out of memory in x_realloc");
|
||||
}
|
||||
if (ptr) {
|
||||
/* Note invalid read as the memcpy reads beyond the memory allocated by ptr */
|
||||
memcpy(p2, ptr, size);
|
||||
free(ptr);
|
||||
}
|
||||
#endif
|
||||
return p2;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
revsusive directory traversal - used for cleanup
|
||||
fn() is called on all files/dirs in the tree
|
||||
*/
|
||||
void traverse(const char *dir, void (*fn)(const char *, struct stat *))
|
||||
{
|
||||
DIR *d;
|
||||
struct dirent *de;
|
||||
|
||||
d = opendir(dir);
|
||||
if (!d) return;
|
||||
|
||||
while ((de = readdir(d))) {
|
||||
char *fname;
|
||||
struct stat st;
|
||||
|
||||
if (strcmp(de->d_name,".") == 0) continue;
|
||||
if (strcmp(de->d_name,"..") == 0) continue;
|
||||
|
||||
if (strlen(de->d_name) == 0) continue;
|
||||
|
||||
x_asprintf(&fname, "%s/%s", dir, de->d_name);
|
||||
#ifdef _WIN32
|
||||
if (stat(fname, &st))
|
||||
#else
|
||||
if (lstat(fname, &st))
|
||||
#endif
|
||||
{
|
||||
if (errno != ENOENT) {
|
||||
perror(fname);
|
||||
}
|
||||
free(fname);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
traverse(fname, fn);
|
||||
}
|
||||
|
||||
fn(fname, &st);
|
||||
free(fname);
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
|
||||
/* return the base name of a file - caller frees */
|
||||
char *str_basename(const char *s)
|
||||
{
|
||||
char *p = strrchr(s, '/');
|
||||
if (p) {
|
||||
s = (p+1);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
p = strrchr(s, '\\');
|
||||
|
||||
if (p) {
|
||||
s = (p+1);
|
||||
}
|
||||
#endif
|
||||
|
||||
return x_strdup(s);
|
||||
}
|
||||
|
||||
/* return the dir name of a file - caller frees */
|
||||
char *dirname(char *s)
|
||||
{
|
||||
char *p;
|
||||
s = x_strdup(s);
|
||||
p = strrchr(s, '/');
|
||||
#ifdef _WIN32
|
||||
p = strrchr(s, '\\');
|
||||
#endif
|
||||
if (p) {
|
||||
*p = 0;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
http://www.ecst.csuchico.edu/~beej/guide/ipc/flock.html
|
||||
http://cvs.php.net/viewvc.cgi/php-src/win32/flock.c?revision=1.2&view=markup
|
||||
Should return 0 for success, >0 otherwise
|
||||
*/
|
||||
int lock_fd(int fd)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
# if 1
|
||||
return _locking(fd, _LK_NBLCK, 1);
|
||||
# else
|
||||
HANDLE fl = (HANDLE)_get_osfhandle(fd);
|
||||
OVERLAPPED o;
|
||||
memset(&o, 0, sizeof(o));
|
||||
return (LockFileEx(fl, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &o))
|
||||
? 0 : GetLastError();
|
||||
# endif
|
||||
#else
|
||||
struct flock fl;
|
||||
int ret;
|
||||
|
||||
fl.l_type = F_WRLCK;
|
||||
fl.l_whence = SEEK_SET;
|
||||
fl.l_start = 0;
|
||||
fl.l_len = 1;
|
||||
fl.l_pid = 0;
|
||||
|
||||
/* not sure why we would be getting a signal here,
|
||||
but one user claimed it is possible */
|
||||
do {
|
||||
ret = fcntl(fd, F_SETLKW, &fl);
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* return size on disk of a file */
|
||||
size_t file_size(struct stat *st)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return (st->st_size + 1023) & ~1023;
|
||||
#else
|
||||
size_t size = st->st_blocks * 512;
|
||||
if ((size_t)st->st_size > size) {
|
||||
/* probably a broken stat() call ... */
|
||||
size = (st->st_size + 1023) & ~1023;
|
||||
}
|
||||
return size;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* a safe open/create for read-write */
|
||||
int safe_open(const char *fname)
|
||||
{
|
||||
int fd = open(fname, O_RDWR|O_BINARY);
|
||||
if (fd == -1 && errno == ENOENT) {
|
||||
fd = open(fname, O_RDWR|O_CREAT|O_EXCL|O_BINARY, 0666);
|
||||
if (fd == -1 && errno == EEXIST) {
|
||||
fd = open(fname, O_RDWR|O_BINARY);
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* display a kilobyte unsigned value in M, k or G */
|
||||
void display_size(unsigned v)
|
||||
{
|
||||
if (v > 1024*1024) {
|
||||
printf("%8.1f Gbytes", v/((double)(1024*1024)));
|
||||
} else if (v > 1024) {
|
||||
printf("%8.1f Mbytes", v/((double)(1024)));
|
||||
} else {
|
||||
printf("%8u Kbytes", v);
|
||||
}
|
||||
}
|
||||
|
||||
/* return a value in multiples of 1024 give a string that can end
|
||||
in K, M or G
|
||||
*/
|
||||
size_t value_units(const char *s)
|
||||
{
|
||||
char m;
|
||||
double v = atof(s);
|
||||
m = s[strlen(s)-1];
|
||||
switch (m) {
|
||||
case 'G':
|
||||
case 'g':
|
||||
default:
|
||||
v *= 1024*1024;
|
||||
break;
|
||||
case 'M':
|
||||
case 'm':
|
||||
v *= 1024;
|
||||
break;
|
||||
case 'K':
|
||||
case 'k':
|
||||
v *= 1;
|
||||
break;
|
||||
}
|
||||
return (size_t)v;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
a sane realpath() function, trying to cope with stupid path limits and
|
||||
a broken API
|
||||
*/
|
||||
char *x_realpath(const char *path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
char namebuf[MAX_PATH];
|
||||
DWORD ret;
|
||||
|
||||
ret = GetFullPathNameA(path, sizeof(namebuf), namebuf, NULL);
|
||||
if (ret == 0 || ret >= sizeof(namebuf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return x_strdup(namebuf);
|
||||
#else
|
||||
int maxlen;
|
||||
char *ret, *p;
|
||||
#ifdef PATH_MAX
|
||||
maxlen = PATH_MAX;
|
||||
#elif defined(MAXPATHLEN)
|
||||
maxlen = MAXPATHLEN;
|
||||
#elif defined(_PC_PATH_MAX)
|
||||
maxlen = pathconf(path, _PC_PATH_MAX);
|
||||
#endif
|
||||
if (maxlen < 4096) maxlen = 4096;
|
||||
|
||||
ret = x_malloc(maxlen);
|
||||
|
||||
#if HAVE_REALPATH
|
||||
p = realpath(path, ret);
|
||||
#else
|
||||
/* yes, there are such systems. This replacement relies on
|
||||
the fact that when we call x_realpath we only care about symlinks */
|
||||
{
|
||||
int len = readlink(path, ret, maxlen-1);
|
||||
if (len == -1) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
ret[len] = 0;
|
||||
p = ret;
|
||||
}
|
||||
#endif
|
||||
if (p) {
|
||||
p = x_strdup(p);
|
||||
free(ret);
|
||||
return p;
|
||||
}
|
||||
free(ret);
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* a getcwd that will returns an allocated buffer */
|
||||
char *gnu_getcwd(void)
|
||||
{
|
||||
unsigned size = 128;
|
||||
|
||||
while (1) {
|
||||
char *buffer = (char *)x_malloc(size);
|
||||
if (getcwd(buffer, size) == buffer) {
|
||||
return buffer;
|
||||
}
|
||||
free(buffer);
|
||||
if (errno != ERANGE) {
|
||||
return 0;
|
||||
}
|
||||
size *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* create an empty file */
|
||||
int create_empty_file(const char *fname)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666);
|
||||
if (fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
return current users home directory or die
|
||||
*/
|
||||
const char *get_home_directory(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
static char home_path[MAX_PATH] = {0};
|
||||
HRESULT ret;
|
||||
|
||||
/* we already have the path */
|
||||
if (home_path[0] != 0) {
|
||||
return home_path;
|
||||
}
|
||||
|
||||
/* get the path to "Application Data" folder */
|
||||
ret = SHGetFolderPathA(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, home_path);
|
||||
if (SUCCEEDED(ret)) {
|
||||
return home_path;
|
||||
}
|
||||
|
||||
fprintf(stderr, "ccache: Unable to determine home directory\n");
|
||||
return NULL;
|
||||
#else
|
||||
const char *p = getenv("HOME");
|
||||
if (p) {
|
||||
return p;
|
||||
}
|
||||
#ifdef HAVE_GETPWUID
|
||||
{
|
||||
struct passwd *pwd = getpwuid(getuid());
|
||||
if (pwd) {
|
||||
return pwd->pw_dir;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
fatal("Unable to determine home directory");
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int x_utimes(const char *filename)
|
||||
{
|
||||
#ifdef HAVE_UTIMES
|
||||
return utimes(filename, NULL);
|
||||
#else
|
||||
return utime(filename, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
/* perror for Win32 API calls, using GetLastError() instead of errno */
|
||||
void perror_win32(LPTSTR pszFunction)
|
||||
{
|
||||
LPTSTR pszMessage;
|
||||
DWORD dwLastError = GetLastError();
|
||||
|
||||
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
dwLastError,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&pszMessage,
|
||||
0, NULL );
|
||||
|
||||
fprintf(stderr, "%s: %s\n", pszFunction, pszMessage);
|
||||
LocalFree(pszMessage);
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,158 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>ccache</TITLE>
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" TEXT="#000000" VLINK="#292555" LINK="#292555" ALINK="#cc0033">
|
||||
<h2>ccache</h2>
|
||||
|
||||
ccache is a compiler cache. It acts as a caching pre-processor to
|
||||
C/C++ compilers, using the -E compiler switch and a hash to detect
|
||||
when a compilation can be satisfied from cache. This often results in
|
||||
a 5 to 10 times speedup in common compilations.<p>
|
||||
|
||||
The idea came from Erik Thiele wrote the original <a
|
||||
href="http://compilercache.sourceforge.net/">compilercache</a> program
|
||||
as a bourne shell script. ccache is a re-implementation of Erik's idea
|
||||
in C with more features and better performance.<p>
|
||||
|
||||
<h2>Latest release</h2>
|
||||
|
||||
The latest release is ccache 2.4.
|
||||
|
||||
<ul>
|
||||
<li>Added CCACHE_READONLY option
|
||||
<li>Added CCACHE_TEMPDIR option
|
||||
<li>fixed handling of hard-linked compilers on AIX
|
||||
<li>added O_BINARY support, to try and support win32 compiles
|
||||
<li>show cache directory in stats output
|
||||
<li>fixed handling of HOME environment variable
|
||||
</ul>
|
||||
|
||||
See the <a href="ccache-man.html">manual page</a> for details
|
||||
on the new options.<p>
|
||||
|
||||
You can get this release from the <a href="http://ccache.samba.org/ftp/ccache/">download directory</a>
|
||||
|
||||
<p>NOTE! This release changes the hash input slighly, so you will
|
||||
probably find that you will not get any hits against your existing
|
||||
cache when you upgrade.
|
||||
|
||||
<h2>Why bother?</h2>
|
||||
|
||||
Why bother with a compiler cache? If you ever run "make clean; make"
|
||||
then you can probably benefit from ccache. It is very common for
|
||||
developers to do a clean build of a project for a whole host of
|
||||
reasons, and this throws away all the information from your previous
|
||||
compiles.<p>
|
||||
|
||||
By using ccache you can get exactly the same effect as "make clean;
|
||||
make" but much faster. It also helps a lot when doing RPM builds,
|
||||
as RPM can make doing incremental builds tricky.<p>
|
||||
|
||||
I put the effort into writing ccache for 2 reasons. The first is the
|
||||
Samba build farm
|
||||
(<a href="http://build.samba.org/">http://build.samba.org/</a>)
|
||||
which constantly does clean builds of Samba on about 30 machines after each
|
||||
CVS commit. On some of those machines the build took over an hour. By
|
||||
using ccache we get the same effect as clean builds but about 6 times
|
||||
faster.<p>
|
||||
|
||||
The second reason is the autobuild system I used to run for
|
||||
Quantum. That system builds our whole Linux based OS from scratch
|
||||
after every CVS commit to catch compilation problems quickly. Using
|
||||
ccache those builds are much faster.
|
||||
|
||||
<h2>Is it safe?</h2>
|
||||
|
||||
Yes. The most important aspect of a compiler cache is to <b>always</b>
|
||||
produce exactly the same output that the real compiler would
|
||||
produce. The includes providing exactly the same object files and
|
||||
exactly the same compiler warnings that would be produced if you use
|
||||
the real compiler. The only way you should be able to tell that you
|
||||
are using ccache is the speed.<p>
|
||||
|
||||
I have coded ccache very carefully to try to provide these guarantees.
|
||||
|
||||
<h2>Features</h2>
|
||||
|
||||
<ul>
|
||||
<li> keeps statistics on hits/misses
|
||||
<li> automatic cache size management
|
||||
<li> can cache compiles that generate warnings
|
||||
<li> easy installation
|
||||
<li> very low overhead
|
||||
<li> uses hard links where possible to avoid copies
|
||||
</ul>
|
||||
|
||||
<h2>Documentation</h2>
|
||||
|
||||
See the <a href="ccache-man.html">manual page</a>
|
||||
|
||||
|
||||
<h2>Performance</h2>
|
||||
|
||||
Here are some results for compiling Samba on my Linux laptop. I have
|
||||
also included the results of using Erik's compilercache program
|
||||
(version 1.0.10) for comparison.<p>
|
||||
|
||||
<table border=1>
|
||||
<tr><th> </th> <th> ccache</th> <th> compilercache</th> </tr>
|
||||
<tr><td>normal </td> <td align=right>13m 4s </td><td align=right>13m 4s</td> </tr>
|
||||
<tr><td>uncached </td> <td align=right>13m 15s </td><td align=right>15m 41s</td> </tr>
|
||||
<tr><td>cached </td> <td align=right>2m 45s </td><td align=right>4m 26s</td> </tr>
|
||||
</table>
|
||||
|
||||
<h2>How to use it</h2>
|
||||
|
||||
You can use ccache in two ways. The first is just to prefix your
|
||||
compile commands with "ccache". For example, you could change the
|
||||
"CC=gcc" line in your Makefile to be "CC=ccache gcc".<p>
|
||||
|
||||
Alternatively, you can create symbolic links from your compilers name
|
||||
to ccache. This allows you to use ccache without any changes to your
|
||||
build system.
|
||||
|
||||
<h2>Download</h2>
|
||||
|
||||
You can download the latest release from the <a
|
||||
href="http://ccache.samba.org/ftp/ccache/">download directory</a>.<p>
|
||||
|
||||
For the bleeding edge, you can fetch ccache via CVS or
|
||||
rsync. To fetch via cvs use the following command:
|
||||
|
||||
<pre>
|
||||
cvs -d :pserver:cvs@pserver.samba.org:/cvsroot co ccache
|
||||
</pre>
|
||||
|
||||
To fetch via rsync use this command:
|
||||
|
||||
<pre>
|
||||
rsync -Pavz samba.org::ftp/unpacked/ccache .
|
||||
</pre>
|
||||
|
||||
<h2>Related projects</h2>
|
||||
|
||||
Here are some related programs you may find interesting
|
||||
|
||||
<ul>
|
||||
<li> <a href="http://distcc.samba.org/">distcc</a> - a distributed compilation system
|
||||
<li> <a href="http://cachecc1.sourceforge.net/">cachecc1</a> - a gcc specific cache
|
||||
<li> <a href="http://sourceforge.net/projects/gocache/">gocache</a> - a cross platform compiler cache
|
||||
</ul>
|
||||
<p>
|
||||
|
||||
<h2>Mailing list</h2>
|
||||
|
||||
<p>A <a href="http://lists.samba.org/mailman/listinfo/ccache/">mailing
|
||||
list</a> is available for discussion of ccache.
|
||||
|
||||
|
||||
<hr>
|
||||
<tiny>
|
||||
<a href="http://samba.org/~tridge/">Andrew Tridgell</a><br>
|
||||
<a href="mailto:bugs@ccache.samba.org">bugs@ccache.samba.org</a>
|
||||
</tiny>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
|
@ -0,0 +1,150 @@
|
|||
Below are the changes for the current release.
|
||||
See the CHANGES file for changes in older releases.
|
||||
See the RELEASENOTES file for a summary of changes in each release.
|
||||
Issue # numbers mentioned below can be found on Github. For more details, add
|
||||
the issue number to the end of the URL: https://github.com/swig/swig/issues/
|
||||
|
||||
Version 4.0.2 (8 Jun 2020)
|
||||
==========================
|
||||
|
||||
2020-06-07 vigsterkr
|
||||
[Ruby] #1717 Nil fix mangling strings
|
||||
|
||||
2020-06-07 vadz
|
||||
#1748 Fix doxygen comments quoting issue
|
||||
|
||||
2020-06-07 munoah
|
||||
#1800 Escape spaces in file paths for dependencies (-M -MM etc)
|
||||
|
||||
2020-06-06 andreas-schwab
|
||||
[Ruby] #1801 Fix encoding on big endian systems when wrapping std::wstring.
|
||||
|
||||
2020-05-31 kwwette
|
||||
[Octave] #1789 error handling improvements and return error code on exit for SWIG wrapped modules.
|
||||
|
||||
2020-05-30 msteinbeck
|
||||
[D] #1593 Replace broken imports when using newer versions of D.
|
||||
|
||||
2020-05-29: ZackerySpytz
|
||||
[Python] #1716 Performance improvements converting strings when using Python >= 3.3.
|
||||
|
||||
2020-05-28: ZackerySpytz
|
||||
#1776 Quite dramatically decrease run times when generating very large interface files by changing
|
||||
some internal memory pool sizes.
|
||||
|
||||
2020-05-28: mcfarljm
|
||||
#1788 Fix handling of Doxygen \endlink command.
|
||||
|
||||
2020-05-24: vapier
|
||||
[Javascript] #1796 Fix pkg-config invocation in configure.
|
||||
|
||||
2020-04-30: kwwette
|
||||
[Octave] Fix exception raising for newer Octave versions
|
||||
Since (at least) Octave 5.1.0, the Octave error() function now raises a C++ exception,
|
||||
which if uncaught immediately exits a SWIG wrapper function, bypassing any cleanup code
|
||||
that may appear after a "fail:" label. This patch adds a "try { ... } catch(...) { }"
|
||||
block around the contents of SWIG wrapper functions to first execute the cleanup code
|
||||
before rethrowing any exception raised. It is backward compatible with earlier versions
|
||||
of Octave where error() does not raise an exception, which will still branch to the
|
||||
"fail:" block to execute cleanup code if an error is encountered.
|
||||
|
||||
Note that the new "try { ... } catch(...) { }" block will localise any local variables
|
||||
used in typemaps that were NOT declared through SWIG's %typemap(...) syntax, so it's
|
||||
possible this could break existing SWIG wrappers which were implicitly sharing local
|
||||
variables between typemaps. This can be fixed, however, by declaring local variables
|
||||
which need to be shared between typemaps through SWIG's %typemap(...) syntax.
|
||||
|
||||
2020-02-18: ryannevell
|
||||
[Lua] #1728 Add support for LUA lightuserdata to SWIG_Lua_ConvertPtr.
|
||||
|
||||
2020-02-18: dmach
|
||||
[Ruby] #1725 Fix gcc -Wcatch-value warnings.
|
||||
|
||||
2020-02-14: treitmayr
|
||||
#1724 Fix wrapping of abstract user-defined conversion operators.
|
||||
|
||||
2020-02-13: ddurham2
|
||||
[Python] #1512 Fix memleak when using STL containers of shared_ptr objects.
|
||||
|
||||
2020-02-06: wsfulton
|
||||
[Python] #1673 #1674 Fix setting 'this' when extending a proxy class with __slots__.
|
||||
|
||||
2020-01-31: vadz
|
||||
[Ruby] #1651 Add std::auto_ptr<> typemaps.
|
||||
|
||||
2020-01-31: ZackerySpytz
|
||||
[Python] #1700 More robust error checking for failures in calls to Python C API:
|
||||
PyBytes_AsStringAndSize() and PyString_AsStringAndSize().
|
||||
|
||||
2020-01-31: vadz
|
||||
[Python] #1710 Fix crash parsing empty docstrings.
|
||||
|
||||
2020-01-30: Alzathar
|
||||
[R] #910 #914 Fix R memory leak on exception.
|
||||
|
||||
2020-01-30: richardbeare
|
||||
[R] #1511 Fix bug wrapping functions. These were previously incorrectly wrapped as if
|
||||
they were variables. This happened when 'get' or 'set' was in the name of the function
|
||||
or method, but sometimes also in some other circumstances. If you were using R
|
||||
attribute syntax to access these methods, you'll need to switch to calling them as R
|
||||
methods.
|
||||
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2020-01-24: etse-dignitas, wsfulton
|
||||
[C#, D, Java] #1533 Fix upcasting for shared_ptr's of templated types.
|
||||
|
||||
2020-01-16: mcfarljm
|
||||
#1643 #1654 When using -doxygen, fix segfault when nameless parameters or vararg parameters
|
||||
are used.
|
||||
|
||||
2020-01-16: mcfarljm
|
||||
#1632 #1659 Fix newline handling for doxygen "///" comments.
|
||||
|
||||
2020-01-14: mcfarljm
|
||||
#1647 #1656 Fix crash handling empty doxygen comments.
|
||||
|
||||
2020-01-14: mcfarljm
|
||||
#1608 Improve doxygen support.
|
||||
- Add support for \param[] commands such as: \param[in].
|
||||
- Optional arguments are marked as 'optional' in pydoc.
|
||||
- Improve support for \code commands so that other languages are supported as code blocks.
|
||||
Support added for java, c and py. For example Python: \code{.py} ... \endcode
|
||||
- Fix doxygen handling of \em and \p tags for Python.
|
||||
|
||||
2020-01-13: wsfulton
|
||||
[Python] #1595 Python -builtin constructors silently ignored keyword arguments.
|
||||
Instead of silenty ignoring them, now a "TypeError: f() takes no keyword arguments"
|
||||
exception is thrown if keyword arguments are used. Hence constructors and normal methods/
|
||||
functions behave in the same way. Note, -keyword should be used with -builtin to obtain
|
||||
keyword argument support.
|
||||
|
||||
2020-01-05: jschueller shadchin
|
||||
[Python] #1670 #1696 Add missing field initializers introduced in python 3.8:
|
||||
tp_vectorcall and tp_print.
|
||||
|
||||
2020-01-05: friedrichatgc
|
||||
[Octave] #1688 Change swig_this() to use size_t instead of long for compatibility
|
||||
with Windows 64 bit.
|
||||
|
||||
2020-01-05: treitmayr
|
||||
[Ruby] #1692 #1689 Add support for Ruby 2.7
|
||||
|
||||
2019-12-30: treitmayr
|
||||
[Ruby] #1653 #1668 Fix code generated when using -globalmodule option.
|
||||
|
||||
2019-12-29: ZackerySpytz
|
||||
[OCaml] #1686 Fix compilation errors with OCaml 4.09.0.
|
||||
|
||||
2019-12-10: wsfulton
|
||||
#1679 Fix parsing of C++11 identifiers with special meaning (final and override) when
|
||||
they are used as part of the scope name of an identifier, such as a namespace name.
|
||||
|
||||
2019-11-26: wsfulton
|
||||
[C#] #1628 'out' or 'ref' used in a cstype typemap was not always stripped out in parts
|
||||
of director code generation.
|
||||
|
||||
2019-11-01: wsfulton
|
||||
[Python] #1595 Fix bug in support for keyword arguments (kwargs feature or -keyword)
|
||||
when using -builtin. The fix is in the argument error checking when wrapping zero
|
||||
argument constructors only.
|
|
@ -0,0 +1,113 @@
|
|||
SWIG Copyright and Authors
|
||||
--------------------------
|
||||
|
||||
Copyright (c) 1995-2011 The SWIG Developers
|
||||
Copyright (c) 2005-2006 Arizona Board of Regents (University of Arizona).
|
||||
Copyright (c) 1998-2005 University of Chicago.
|
||||
Copyright (c) 1995-1998 The University of Utah and the Regents of the University of California
|
||||
|
||||
Portions also copyrighted by:
|
||||
Network Applied Communication Laboratory, Inc
|
||||
Information-technology Promotion Agency, Japan
|
||||
|
||||
Active SWIG Developers:
|
||||
William Fulton (wsf@fultondesigns.co.uk) (SWIG core, Java, C#, Windows, Cygwin)
|
||||
Olly Betts (olly@survex.com) (PHP)
|
||||
Joseph Wang (joequant@gmail.com) (R)
|
||||
Xavier Delacour (xavier.delacour@gmail.com) (Octave)
|
||||
David Nadlinger (code@klickverbot.at) (D)
|
||||
Oliver Buchtala (oliver.buchtala@gmail.com) (Javascript)
|
||||
Neha Narang (narangneha03@gmail.com) (Javascript)
|
||||
Simon Marchetto (simon.marchetto@scilab-enterprises.com) (Scilab)
|
||||
Zackery Spytz (zspytz@gmail.com) (OCaml, SWIG core)
|
||||
|
||||
Past SWIG developers and major contributors include:
|
||||
Dave Beazley (dave-swig@dabeaz.com) (SWIG core, Python, Tcl, Perl)
|
||||
Henning Thielemann (swig@henning-thielemann.de) (Modula3)
|
||||
Matthias Köppe (mkoeppe@mail.math.uni-magdeburg.de) (Guile, MzScheme)
|
||||
Luigi Ballabio (luigi.ballabio@fastwebnet.it) (STL wrapping)
|
||||
Mikel Bancroft (mikel@franz.com) (Allegro CL)
|
||||
Surendra Singhi (efuzzyone@netscape.net) (CLISP, CFFI)
|
||||
Marcelo Matus (mmatus@acms.arizona.edu) (SWIG core, Python, UTL[python,perl,tcl,ruby])
|
||||
Art Yerkes (ayerkes@speakeasy.net) (OCaml)
|
||||
Lyle Johnson (lyle@users.sourceforge.net) (Ruby)
|
||||
Charlie Savage (cfis@interserv.com) (Ruby)
|
||||
Thien-Thi Nguyen (ttn@glug.org) (build/test/misc)
|
||||
Richard Palmer (richard@magicality.org) (PHP)
|
||||
Sam Liddicott - Ananova Ltd (saml@liddicott.com) (PHP)
|
||||
Tim Hockin - Sun Microsystems (thockin@sun.com) (PHP)
|
||||
Kevin Ruland (PHP)
|
||||
Shibukawa Yoshiki (Japanese Translation)
|
||||
Jason Stewart (jason@openinformatics.com) (Perl5)
|
||||
Loic Dachary (Perl5)
|
||||
David Fletcher (Perl5)
|
||||
Gary Holt (Perl5)
|
||||
Masaki Fukushima (Ruby)
|
||||
Scott Michel (scottm@cs.ucla.edu) (Java directors)
|
||||
Tiger Feng (songyanf@cs.uchicago.edu) (SWIG core)
|
||||
Mark Rose (mrose@stm.lbl.gov) (Directors)
|
||||
Jonah Beckford (beckford@usermail.com) (CHICKEN)
|
||||
Ahmon Dancy (dancy@franz.com) (Allegro CL)
|
||||
Dirk Gerrits (Allegro CL)
|
||||
Neil Cawse (C#)
|
||||
Harco de Hilster (Java)
|
||||
Alexey Dyachenko (dyachenko@fromru.com) (Tcl)
|
||||
Bob Techentin (Tcl)
|
||||
Martin Froehlich <MartinFroehlich@ACM.org> (Guile)
|
||||
Marcio Luis Teixeira <marciot@holly.colostate.edu> (Guile)
|
||||
Duncan Temple Lang (R)
|
||||
Miklos Vajna <vmiklos@frugalware.org> (PHP directors)
|
||||
Mark Gossage (mark@gossage.cjb.net) (Lua)
|
||||
Raman Gopalan (ramangopalan@gmail.com) (eLua)
|
||||
Gonzalo Garramuno (ggarra@advancedsl.com.ar) (Ruby, Ruby's UTL)
|
||||
John Lenz (Guile, MzScheme updates, Chicken module, runtime system)
|
||||
Baozeng Ding <sploving1@163.com> (Scilab)
|
||||
Ian Lance Taylor (Go)
|
||||
Dmitry Kabak (userdima@gmail.com) (Doxygen)
|
||||
Vadim Zeitlin (PCRE, Python, Doxygen)
|
||||
Stefan Zager (szager@gmail.com) (Python)
|
||||
Vincent Couvert (Scilab)
|
||||
Sylvestre Ledru (Scilab)
|
||||
Wolfgang Frisch (Scilab)
|
||||
|
||||
Past contributors include:
|
||||
James Michael DuPont, Clark McGrew, Dustin Mitchell, Ian Cooke, Catalin Dumitrescu, Baran
|
||||
Kovuk, Oleg Tolmatcev, Tal Shalif, Lluis Padro, Chris Seatory, Igor Bely, Robin Dunn,
|
||||
Edward Zimmermann, David Ascher, Dominique Dumont, Pier Giorgio Esposito, Hasan Baran Kovuk,
|
||||
Klaus Wiederänders, Richard Beare, Hans Oesterholt.
|
||||
(See CHANGES and CHANGES.current and the bug tracker for a more complete list).
|
||||
|
||||
Past students:
|
||||
Songyan Feng (Chicago).
|
||||
Xinghua Shi (Chicago).
|
||||
Jing Cao (Chicago).
|
||||
Aquinas Hobor (Chicago).
|
||||
|
||||
Historically, the following people contributed to early versions of SWIG.
|
||||
Peter Lomdahl, Brad Holian, Shujia Zhou, Niels Jensen, and Tim Germann
|
||||
at Los Alamos National Laboratory were the first users. Patrick
|
||||
Tullmann at the University of Utah suggested the idea of automatic
|
||||
documentation generation. John Schmidt and Kurtis Bleeker at the
|
||||
University of Utah tested out the early versions. Chris Johnson
|
||||
supported SWIG's developed at the University of Utah. John Buckman,
|
||||
Larry Virden, and Tom Schwaller provided valuable input on the first
|
||||
releases and improving the portability of SWIG. David Fletcher and
|
||||
Gary Holt have provided a great deal of input on improving SWIG's
|
||||
Perl5 implementation. Kevin Butler contributed the first Windows NT
|
||||
port.
|
||||
|
||||
Early bug reports and patches:
|
||||
Adam Hupp, Arthur Smyles, Brad Clements, Brett Williams, Buck Hodges,
|
||||
Burkhard Kloss, Chia-Liang Kao, Craig Files, Dennis Marsa, Dieter Baron,
|
||||
Drake Diedrich, Fleur Diana Dragan, Gary Pennington, Geoffrey Hort, Gerald Williams,
|
||||
Greg Anderson, Greg Kochanski, Greg Troxel, Henry Rowley, Irina Kotlova,
|
||||
Israel Taller, James Bailey, Jim Fulton, Joel Reed, Jon Travis,
|
||||
Junio Hamano, Justin Heyes-Jones, Karl Forner, Keith Davidson,
|
||||
Krzysztof Kozminski, Larry Virden, Luke J Crook, Magnus Ljung, Marc Zonzon,
|
||||
Mark Howson, Micahel Scharf, Michel Sanner, Mike Romberg, Mike Simons,
|
||||
Mike Weiblen, Paul Brannan, Ram Bhamidipaty, Reinhard Fobbe, Rich Wales,
|
||||
Richard Salz, Roy Lecates, Rudy Albachten, Scott Drummonds
|
||||
Scott Michel, Shaun Lowry, Steve Galser, Tarn Weisner Burton,
|
||||
Thomas Weidner, Tony Seward, Uwe Steinmann, Vadim Chugunov, Wyss Clemens,
|
||||
Zhong Ren.
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>SWIG Command Line Handling</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<center>
|
||||
<h1>SWIG Command Line Handling</h1>
|
||||
|
||||
<p>
|
||||
David M. Beazley <br>
|
||||
dave-swig@dabeaz.com<br>
|
||||
December, 2006<br>
|
||||
|
||||
</b>
|
||||
</center>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
This document describes the functions related to the handling of
|
||||
command line options passed to SWIG. These functions are defined in
|
||||
the header file <tt>Source/Swig/swigopt.h</tt>. This API is
|
||||
considered to be stable.
|
||||
|
||||
<h2>Initialization</h2>
|
||||
|
||||
Upon SWIG startup, the following function is called:
|
||||
|
||||
<p>
|
||||
<b><tt>void Swig_init_args(int argc, char **argv_)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Registers command line options with the SWIG core. This creates an internal array that is used by other
|
||||
functions to mark whether or not a particular command line option was used. This is ultimately used to issue error messages about unused or unknown command line options. This function is currently invoked in the SWIG main() function that is found in <tt>Source/Modules/swigmain.cxx</tt>.
|
||||
</blockquote>
|
||||
|
||||
<h2>Argument Marking</h2>
|
||||
|
||||
As command line options are processed by language modules, the following functions are used
|
||||
to mark the arguments as used:
|
||||
|
||||
<p>
|
||||
<b><tt>void Swig_mark_arg(int n)</tt></b>
|
||||
<blockquote>
|
||||
Mark argument number <tt>n</tt> as used.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>int Swig_check_marked(int n)</tt></b>
|
||||
<blockquote>
|
||||
Check to see if argument <tt>n</tt> has been marked. Returns 0 or 1.
|
||||
</blockquote>
|
||||
|
||||
<h2>Argument Checking</h2>
|
||||
|
||||
The following function is used to check all of the command line options after parsing. It looks at the marked list
|
||||
and issues an error message if any unconsumed arguments are found.
|
||||
|
||||
<p>
|
||||
<b><tt>void Swig_check_options()</tt></b>
|
||||
<blockquote>
|
||||
Checks all command line options to see if they have all been processed. If not, an error message is generated and
|
||||
execution terminates with a call to <tt>exit()</tt>. This function is currently invoked in <tt>Source/Modules/main.cxx</tt> just before SWIG starts any processing of input files.
|
||||
</blockquote>
|
||||
|
||||
<h2>Utility Function</h2>
|
||||
<p>
|
||||
<b><tt>void Swig_arg_error())</tt></b>
|
||||
|
||||
<blockquote>
|
||||
A generic function that issues an error message about being unable to parse command line options. SWIG is terminated by a call to <tt>exit()</tt>.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,404 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>SWIG Engineering Manual</title>
|
||||
</head>
|
||||
<body bgcolor="#ffffff">
|
||||
<center>
|
||||
<h1>SWIG Engineering Manual</h1>
|
||||
|
||||
<b>David Beazley <br>
|
||||
</b>
|
||||
</center>
|
||||
|
||||
<p>
|
||||
(Note : This is a work in progress.)
|
||||
|
||||
<h2>Table of Contents</h2>
|
||||
<ul>
|
||||
<li><a name="i1" href="#1">1. Introduction</a>
|
||||
<li><a name="i2" href="#2">2. Programming Languages and Libraries</a>
|
||||
<li><a name="i3" href="#3">3. The Source Directory and Module Names</a>
|
||||
<li><a name="i4" href="#4">4. Include Files</a>
|
||||
<li><a name="i5" href="#5">5. File Structure</a>
|
||||
<li><a name="i6" href="#6">6. Bottom-Up Design</a>
|
||||
<li><a name="i7" href="#7">7. Functions</a>
|
||||
<li><a name="i8" href="#8">8. Naming Conventions</a>
|
||||
<li><a name="i9" href="#9">9. Visibility</a>
|
||||
<li><a name="i10" href="#10">10. Miscellaneous Coding Guidelines</a>
|
||||
<li><a name="i11" href="#11">11. Git Tagging Conventions</a>
|
||||
</ul>
|
||||
|
||||
<a name="1" href="#i1">
|
||||
<h2>1. Introduction</h2>
|
||||
</a>
|
||||
|
||||
The purpose of this document is to describe various coding conventions
|
||||
and organizational aspects for SWIG developers. The idea for this
|
||||
document is largely borrowed from John Ousterhout's Tcl/Tk Engineering
|
||||
Manual. It is not my intent to overly managerial about matters--rather I'm
|
||||
hoping to make life a little less chaotic for everyone.
|
||||
|
||||
<p>
|
||||
First a little background: SWIG was started in 1995 as a one-person
|
||||
project and continued in this mode of operation until about 1998.
|
||||
Most of this development was driven by ideas submitted by early SWIG
|
||||
users as opposed to being motivated by a grand design. As a result,
|
||||
the code ended up being a pretty horrible C++ coding disaster. A
|
||||
mostly working disaster perhaps, but a disaster nonetheless.
|
||||
|
||||
<p>
|
||||
With that said, the primary goal of future SWIG development is to
|
||||
reengineer the original system, fix most of its inherent design flaws,
|
||||
and to produce what I hope will become a highly extensible and modular
|
||||
interface compiler framework. To this do this, there are a few
|
||||
critical areas of work. First, I want to restructure SWIG as a
|
||||
collection of loosely coupled modules written in either ANSI C or an
|
||||
scripting language. Second, I want the system to be minimalistic in
|
||||
its use of data structures and interconnections. The primary reason
|
||||
for this is that the fewer data structures there are, the less users
|
||||
will have to remember. This will also make the system more accessible
|
||||
to non-experts. Finally, I want to reevaluate the whole idea of a
|
||||
SWIG module is and expand the definition to include just about
|
||||
anything from parsers, preprocessors, optimizers, interface editors,
|
||||
and code generators.
|
||||
|
||||
<p>
|
||||
The rest of this document outlines a few general rules of how code
|
||||
should be developed within the SWIG project. These rules are
|
||||
primarily drawn from my own experience developing software and
|
||||
observing the practices of other successful projects.
|
||||
|
||||
<a name="2" href="#i2">
|
||||
<h2>2. Programming Languages and Libraries </h2>
|
||||
</a>
|
||||
|
||||
All SWIG modules must be written in either ANSI C or one of the
|
||||
scripting languages for which SWIG can generate an interface (e.g.,
|
||||
Perl, Python, or Tcl). C++ is currently being used to write
|
||||
SWIG modules, but it is only being utilized to avoid working with
|
||||
a lot of pointers to functions. <b>Advanced C++ features like namespaces, templates,
|
||||
and overloading should not be used.</b>.
|
||||
|
||||
<p>
|
||||
Module writers should make every attempt to use only those functions
|
||||
described in the POSIX.1 standard. This includes most of the
|
||||
functions contained the Kernighan and Ritchie C programming book. Use
|
||||
of operating system dependent functionality such as socket libraries
|
||||
should always be included inside a conditional compilation block so
|
||||
that it can be omitted on problematic platforms. If you are unsure
|
||||
about a library call, check the man page or contact Dave.
|
||||
|
||||
<a name="3" href="#i3">
|
||||
<h2>3. The Source Directory and Module Names</h2>
|
||||
</a>
|
||||
|
||||
All SWIG modules are contained within the "Source" directory. Within
|
||||
this directory, each module is placed into its own subdirectory. The
|
||||
name of this subdirectory should exactly match the name of the module.
|
||||
For example, if you are creating a module called "Tcl", all of your
|
||||
files should be placed in a directory "Tcl".
|
||||
|
||||
<p>
|
||||
When choosing a module name, please pick a name that is not
|
||||
currently in use. As a general convention, the first letter of a
|
||||
module name is capitalized such as "Perl". Alternatives such as
|
||||
"perl" or "PERL" should be avoided. In certain instances, the first
|
||||
two letters may be capitalized as in "CParse." The exact usage of
|
||||
this is somewhat inconsistent and isn't terribly important--just make
|
||||
sure the first letter is capitalized. Also, module names should not
|
||||
start with numbers, include underscores or any other special
|
||||
non-alphanumeric characters.
|
||||
|
||||
<a name="5" href="#i5">
|
||||
<h2>5. File Structure </h2>
|
||||
</a>
|
||||
|
||||
Each file in a module should be given a filename that is all lowercase letters
|
||||
such as "parser.c", not "Parser.c" or "PARSER.c". Please note that filenames
|
||||
are case-insensitive on Windows so this convention will prevent you from inadvertently
|
||||
creating two files that differ in case-only.
|
||||
|
||||
<p>
|
||||
Each file should include a short abstract and license information
|
||||
like this:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
/* -----------------------------------------------------------------------------
|
||||
* This file is part of SWIG, which is licensed as a whole under version 3
|
||||
* (or any later version) of the GNU General Public License. Some additional
|
||||
* terms also apply to certain portions of SWIG. The full details of the SWIG
|
||||
* license and copyrights can be found in the LICENSE and COPYRIGHT files
|
||||
* included with the SWIG source code as distributed by the SWIG developers
|
||||
* and at http://www.swig.org/legal.html.
|
||||
*
|
||||
* xxx.c
|
||||
*
|
||||
* This file defines ...
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
#include "swig.h"
|
||||
|
||||
/* Declarations */
|
||||
typedef struct {
|
||||
int x, y;
|
||||
} Foo;
|
||||
|
||||
...
|
||||
|
||||
/* Private Declarations (used only in this file) */
|
||||
static int avariable;
|
||||
|
||||
...
|
||||
|
||||
/* Functions */
|
||||
...
|
||||
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
As a general rule, files start to get unmanageable once they exceed
|
||||
about 2000 lines. Files larger than this should be broken up into
|
||||
multiple files. Similarly, you should avoid the temptation to create
|
||||
many small files as this increases compilation time and makes the
|
||||
directory structure too complicated.
|
||||
|
||||
<a name="6" href="#i6">
|
||||
<h2>6. Bottom-Up Design </h2>
|
||||
</a>
|
||||
|
||||
Within each source file, the preferred organization is to use what is
|
||||
known as "bottom-up" design. Under this scheme, lower-level functions
|
||||
appear first and the highest level function appears last. The easy
|
||||
way to remember is that the "main" function of your module should
|
||||
always appear last in the source file. For example:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
/* Simple bottom-up program */
|
||||
#include <stdio.h>
|
||||
|
||||
int foo(int x, int y) {
|
||||
/* Implement foo */
|
||||
...
|
||||
}
|
||||
|
||||
int bar() {
|
||||
...
|
||||
foo(i,j);
|
||||
...
|
||||
}
|
||||
|
||||
...
|
||||
int main(int argc, char **argv) {
|
||||
...
|
||||
bar();
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
This choice of design is somewhat arbitrary however it has a number of
|
||||
benefits particular to C. In particular, a bottom-up design generally
|
||||
eliminates the need to include forward references--resulting in
|
||||
cleaner code and fewer compilation errors.
|
||||
|
||||
<a name="7" href="#i7">
|
||||
<h2>7. Functions</h2>
|
||||
</a>
|
||||
|
||||
All functions should have a function header that gives the function name
|
||||
and a short description like this:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
/* -------------------------------------------------------------------------
|
||||
* Swig_add_directory()
|
||||
*
|
||||
* Adds a directory to the SWIG search path.
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
void
|
||||
Swig_add_directory(DOH *dirname) {
|
||||
...
|
||||
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
In the function declaration, the return type and any specifiers
|
||||
(extern or static) should appear on a separate line followed by the
|
||||
function name and arguments as shown above. The left curly brace
|
||||
should appear on the same line as the function name.
|
||||
|
||||
<p>
|
||||
Function declarations should <b>NOT</b> use the pre-ANSI function
|
||||
declaration syntax. The ANSI standard has been around long enough for
|
||||
this to be a non-issue.
|
||||
|
||||
<a name="8" href="#i8">
|
||||
<h2>8. Naming Conventions</h2>
|
||||
</a>
|
||||
|
||||
The following conventions are used to name various objects throughout SWIG.
|
||||
|
||||
<h4>Functions</h4>
|
||||
|
||||
Functions should consist of the module name and the function name separated by an underscore like this:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
Preprocessor_define()
|
||||
Swig_add_directory()
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
In general, the module name should match the name of the module
|
||||
subdirectory and the function name should be in all lowercase with
|
||||
words separated by underscores.
|
||||
|
||||
<h4>Structures and Types</h4>
|
||||
|
||||
If your module defines new structures, the structure name should include the name of the
|
||||
module and the name of the structure appended together like this:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
typedef struct SwigScanner {
|
||||
...
|
||||
} SwigScanner;
|
||||
|
||||
typedef struct LParseType {
|
||||
...
|
||||
} LParseType;
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
In this case, both the name of the module and the type should be capitalized. Also, whenever
|
||||
possible, you should use the "typedef struct Name { ... } Name" form when defining new
|
||||
data structures.
|
||||
|
||||
<h4>Global Variables</h4>
|
||||
|
||||
Global variables should be avoided if at all possible. However, if you must use a global
|
||||
variable, please prepend the module name and use the same naming scheme as for functions.
|
||||
|
||||
<h4>Constants</h4>
|
||||
|
||||
Constants should be created using #define and should be in all caps like this:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
#define SWIG_TOKEN_LPAREN 1
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
Separate words in a constant should be separated by underscores as with functions.
|
||||
|
||||
<h4>Structure members</h4>
|
||||
|
||||
Structure members should be in all lower-case and follow the same word-separation convention
|
||||
as for function names. However, the module name does not have to be included.
|
||||
For example:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
typedef struct SwigScanner {
|
||||
DOH *text; /* Current token value */
|
||||
DOH *scanobjs; /* Objects being scanned */
|
||||
DOH *str; /* Current object being scanned */
|
||||
char *idstart; /* Optional identifier start characters */
|
||||
int next_token; /* Next token to be returned */
|
||||
int start_line; /* Starting line of certain declarations */
|
||||
int yylen; /* Length of text pushed into text */
|
||||
DOH *file; /* Current file name */
|
||||
} SwigScanner;
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h4>Static Functions and Variables </h4>
|
||||
|
||||
Static declarations are free to use any naming convention that is appropriate. However, most
|
||||
existing parts of SWIG use lower-case names and follow the same convention as described for functions.
|
||||
|
||||
<a name="9" href="#i9">
|
||||
<h2>9. Visibility</h2>
|
||||
</a>
|
||||
|
||||
Modules should keep the following rules in mind when exposing their internals:
|
||||
|
||||
<ul>
|
||||
<li>Only publicly accessible functions should be included in the module header file.
|
||||
<li>All non-static declarations must be prepended with some form of the module name
|
||||
to avoid potential linker namespace conflicts with other modules.
|
||||
<li>Modules should not expose global variables or use global variables in their
|
||||
public interface.
|
||||
<li>Similarly, modules should discourage the direct manipulation of data contained
|
||||
within data structures in favor of using function calls instead. For example,
|
||||
instead of providing a user with a structure like this:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
typedef struct Foo {
|
||||
int line;
|
||||
} Foo;
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
It is better to hide the implementation of Foo and provide an
|
||||
function-call interface like this:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
typedef struct Foo Foo;
|
||||
extern int Foo_getline(Foo *f);
|
||||
extern void Foo_setline(Foo *f, int line);
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
Although this results in worse performance, there are many practical
|
||||
reasons for doing this. The most important reason is that it allows
|
||||
you to change the internal representation of Foo without breaking all
|
||||
of the other modules or having to recompile the entire universe after
|
||||
making your changes.
|
||||
|
||||
</ul>
|
||||
|
||||
<a name="10" href="#i10">
|
||||
<h2>10. Miscellaneous Coding Guidelines</h2>
|
||||
</a>
|
||||
These are largely covered in the main documentation in the Extending.html file.
|
||||
|
||||
<a name="11" href="#i11">
|
||||
<h2>11. Git Tagging Conventions</h2>
|
||||
</a>
|
||||
|
||||
Use <tt>git tag</tt> to declare some set of file revisions as related in some
|
||||
symbolic way. This eases reference, retrieval and manipulation of these files
|
||||
later. At the moment (2001/01/16 14:02:53), the conventions are very simple;
|
||||
let's hope they stay that way!
|
||||
|
||||
<p>
|
||||
There are two types of tags, internal (aka personal) and external.
|
||||
Internal tags are used by SWIG developers primarily, whereas external
|
||||
tags are used when communicating with people w/ anonymous git access.
|
||||
<ul>
|
||||
<li> Internal tags should start with the developer name and a hyphen.
|
||||
<li> External tags should start with "rel-".
|
||||
</ul>
|
||||
|
||||
That's all there is to it. Some example tags:
|
||||
|
||||
<ul>
|
||||
<li> ttn-pre-xml-patch
|
||||
<li> ttn-post-xml-patch
|
||||
<li> ttn-going-on-vacation-so-dutifully-tagging-now
|
||||
<li> rel-1.3.40
|
||||
<li> rel-2.0.9
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
Copyright (C) 1999-2004 SWIG Development Team.
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,181 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>SWIG File Handling</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<center>
|
||||
<h1>SWIG File Handling</h1>
|
||||
|
||||
<p>
|
||||
David M. Beazley <br>
|
||||
dave-swig@dabeaz.com<br>
|
||||
December, 2006<br>
|
||||
|
||||
</b>
|
||||
</center>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
This document describes the functions related to file and filename handling in the SWIG core. These functions are
|
||||
defined in the header file <tt>Source/Swig/swigfile.h</tt>. This API is considered to be stable.
|
||||
|
||||
<h2>File Search Path</h2>
|
||||
|
||||
These functions manipulate the search path for locating files.
|
||||
|
||||
<p>
|
||||
<b><tt>List *Swig_add_directory(const String_or_char *dirname)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Adds a new directory to the system search path. The directory is appended to
|
||||
the end of the search path. Returns a list containing the current
|
||||
system search path.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void Swig_push_directory(const String_or_char *dirname)</tt></b>
|
||||
<blockquote>
|
||||
Pushes a temporary directory onto the search path. This directory is searched before
|
||||
directories added with <tt>Swig_add_directory()</tt> except when including a system
|
||||
file explicitly (either using #include <file> or calling <tt>Swig_include_sys()</tt>).
|
||||
This function is normally used by the preprocessor to add temporary directories when
|
||||
processing #include statements.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void Swig_pop_directory()</tt></b>
|
||||
<blockquote>
|
||||
Pops off the last pushed directory with <tt>Swig_push_directory()</tt>
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>int Swig_get_push_dir()</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Returns a flag that indicates whether directory pushing is enabled or not.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void Swig_set_push_dir(int dopush)</tt></b>
|
||||
<blockquote>
|
||||
Enables or disables directory pushing. By default, it is turned on. However, the <tt>-I-</tt> command line
|
||||
option to SWIG disables it.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>List *Swig_search_path()</tt></b>
|
||||
<blockquote>
|
||||
Returns the current search path.
|
||||
</blockquote>
|
||||
|
||||
|
||||
<h2>File access functions</h2>
|
||||
|
||||
<p>
|
||||
<b><tt>FILE *Swig_open(const String_or_char *name)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Opens a file, using the applicable search paths, and returns an open <tt>FILE *</tt> object if found. Returns NULL if the file is not found.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>String *Swig_read_file(FILE *f)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Reads all of the data from an open file into a string which is returned.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>String *Swig_include(const String_or_char *name)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Searches for an include file <tt>name</tt> and returns its contents as
|
||||
a string if found. Returns NULL if not found. All of the applicable
|
||||
search paths are searched when trying to locate the file.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>String *Swig_include_sys(const String_or_char *name)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Searches for an include file <tt>name</tt> and returns its contents as
|
||||
a string if found. Returns NULL if not found. All of the applicable
|
||||
search paths are searched when trying to locate the file, but
|
||||
preference is given to system paths first. This mimics the behavior
|
||||
of <tt>#include <file></tt> in the preprocessor.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>int Swig_insert_file(const String_or_char *name, File *outfile)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Searches for a file <tt>name</tt> and dumps its contents to <tt>outfile</tt> if found.
|
||||
Returns 0 on success, -1 if the file couldn't be found.
|
||||
</blockquote>
|
||||
|
||||
<h2>Query functions</h2>
|
||||
|
||||
<p>
|
||||
<b><tt>String *Swig_last_file()</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Returns the full pathname of the file last opened or included.
|
||||
</blockquote>
|
||||
|
||||
<h2>Named files</h2>
|
||||
|
||||
<p>
|
||||
<b><tt>void *Swig_register_filebyname(const String_or_char *filename, File *outfile)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Registers a file object <tt>outfile</tt> with a specific name <tt>filename</tt>. This function is
|
||||
used to implement the SWIG %insert directive and to manage different sections of the output
|
||||
file such as "runtime","header","wrapper","init", etc. Different language modules may add their own
|
||||
sections for generating Python code, Perl code, etc.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>File *Swig_filebyname(const String_or_char *filename)</tt></b>
|
||||
<blockquote>
|
||||
This looks up a file object previously registered using <tt>Swig_register_filebyname()</tt>. This
|
||||
is used to implement the %insert directive.
|
||||
</blockquote>
|
||||
|
||||
<h2>Filename utilities</h2>
|
||||
|
||||
<p>
|
||||
<b><tt>char *Swig_file_suffix(const String_or_char *filename)</tt></b>
|
||||
<blockquote>
|
||||
Returns the suffix of a filename. For instance, if the filename is "foo.txt", it returns ".txt".
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>char *Swig_file_basename(const String_or_char *filename)</tt></b>
|
||||
<blockquote>
|
||||
Returns the filename without the suffix attached to it. For instance, if the filename is "foo.txt", it returns
|
||||
"foo". The result is stored in a static variable. If you need to save it, make your own copy.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>char *Swig_file_filename(const String_or_char *filename)</tt></b>
|
||||
<blockquote>
|
||||
Returns the filename without any leading directories. For instance, if the filename is "/bar/spam/foo.txt", it
|
||||
returns "foo.txt". This function is aware of local naming conventions on the machine (e.g., forward versus back slashes on Unix and Windows). The result is stored in a static variable. If you need to save the value, make a copy.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>char *Swig_file_dirname(const String_or_char *filename)</tt></b>
|
||||
<blockquote>
|
||||
Returns the directory name (if any). For instance, if the filename is "/bar/spam/foo.txt", it
|
||||
returns "/bar/spam/". This function is aware of local naming conventions on the machine (e.g., forward versus back slashes on Unix and Windows). The result is stored in a static variable. If you need to save the value, make a copy.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>SWIG_FILE_DELIMITER</tt></b>
|
||||
<blockquote>
|
||||
This macro contains the file delimiter string for the local machine. On Unix it is "/", on Windows it is "\\".
|
||||
</blockquote>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,31 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>SWIG Documentation</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
This directory contains SWIG documentation:
|
||||
|
||||
<ul>
|
||||
<li><a href="engineering.html">Engineering Manual</a>
|
||||
<li><a href="internals.html">Internals Manual</a>
|
||||
<li><a href="migrate.txt">SWIG1.3 Migration Guide</a>
|
||||
</ul>
|
||||
|
||||
The following documentation describe the internal APIs used by SWIG. These may be useful to module developers.
|
||||
|
||||
<ul>
|
||||
<li><a href="file.html">File handling functions</a>
|
||||
<li><a href="cmdopt.html">Command line arguments</a>
|
||||
<li><a href="tree.html">Parse tree navigation and manipulation</a>
|
||||
<li><a href="parm.html">Parameter and Parameter list handling functions</a>
|
||||
<li><a href="scanner.html">Generic C/C++ Scanner interface</a>
|
||||
<li><a href="wrapobj.html">Wrapper objects</a>.
|
||||
<li><a href="runtime.txt">SWIG Runtime</a>.
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
Copyright (C) 1999-2007 SWIG Development Team.
|
||||
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,140 @@
|
|||
SWIG1.3 Migration Guide
|
||||
(The not entirely complete guide to updating language modules to work with SWIG1.3).
|
||||
|
||||
Dave Beazley
|
||||
August 15, 2000
|
||||
|
||||
1. Introduction
|
||||
---------------
|
||||
|
||||
Virtually all of SWIG's internal data structures have now been
|
||||
rewritten. Take everything you thought you knew about SWIG1.1 and
|
||||
throw it out.
|
||||
|
||||
2. DataTypes
|
||||
------------
|
||||
The old 'DataType' data structure is gone. Therefore, direct
|
||||
manipulation of 'is_pointer', 'implicit_ptr', and 'arraystr'
|
||||
attributes no longer applies. Sorry.
|
||||
|
||||
Datatypes are now represented by the type 'SwigType' which has no
|
||||
public attributes. Actually, if you look at it closely, 'SwigType' is
|
||||
really just an alias for 'void' and if you look at it even closer than
|
||||
that you will realize that it's nothing more than a string!
|
||||
|
||||
The string encoding of types is described in more detail in the file
|
||||
Source/Swig/stype.c and is not so important here. What is important is
|
||||
the functions used to produce various types of output:
|
||||
|
||||
SwigType_str(type,name = 0);
|
||||
This produces an exact C representation of the datatype with all
|
||||
qualifiers, arrays, references, and so forth. name is an optional
|
||||
name that is given if you wanted to associate the type with a
|
||||
parameter name or something.
|
||||
|
||||
SwigType_lstr(type,name = 0);
|
||||
This function takes a type and produces a C string containing
|
||||
a type suitable for assignment (appearing as an lvalue in an
|
||||
expression). To do this, certain things such as 'const',
|
||||
arrays, and references are stripped away or converted into
|
||||
pointers.
|
||||
|
||||
SwigType_ltype(type);
|
||||
Returns a SwigType object corresponding to the type created
|
||||
by SwigType_lstr().
|
||||
|
||||
SwigType_lcaststr(type,name);
|
||||
Produces a string casting a value 'name' from the real datatype
|
||||
to the assignable type created by SwigType_lstr().
|
||||
|
||||
SwigType_rcaststr(type,name)
|
||||
Produces a string that casts a value 'name' from the type
|
||||
created by SwigType_lstr() to the real datatype.
|
||||
|
||||
SwigType_manglestr(type)
|
||||
Produces the 'mangled' version of a datatype.
|
||||
|
||||
|
||||
Getting the 'type' code. Most language modules still operate by
|
||||
looking at special integer type codes. This interface is a little
|
||||
ragged and will probably go away at some point. However, for now the
|
||||
following function can be used to get the type code:
|
||||
|
||||
int SwigType_type(type)
|
||||
|
||||
The codes are the same as the before, except that there are a few
|
||||
special codes:
|
||||
|
||||
T_STRING - The 'char *' type and variations.
|
||||
T_POINTER - Any pointer type (not char * though)
|
||||
T_REFERENCE - Any C++ reference
|
||||
T_ARRAY - Any array
|
||||
T_FUNCTION - A function (this is usually an error).
|
||||
|
||||
Because of the special codes, it is no longer necessary to have code like this:
|
||||
|
||||
if ((t->is_pointer == 1) and (t->type == T_CHAR)) {
|
||||
... get a string ...
|
||||
}
|
||||
|
||||
Instead, just use the type code above like this:
|
||||
|
||||
switch(SwigType_type(type)) {
|
||||
case T_STRING:
|
||||
... get a string ...
|
||||
break;
|
||||
case T_POINTER:
|
||||
... get a pointer ...
|
||||
break;
|
||||
}
|
||||
|
||||
There are about 2-dozen type manipulation functions that could also be useful.
|
||||
See Source/Swig/swig.h and Source/Swig/stype.c.
|
||||
|
||||
3. Parameter Lists
|
||||
------------------
|
||||
|
||||
The ParmList data structure is gone. In reality, parameter lists are nothing more than
|
||||
a linked list of parameters. The proper way to iterate over this list and get
|
||||
parameter values is as follows:
|
||||
|
||||
ParmList *l;
|
||||
Parm *p;
|
||||
|
||||
for (p = l; p; p = Getnext(p)) {
|
||||
SwigType *pt = Gettype(p); /* Get parameter type */
|
||||
String *pn = Getname(p); /* Get parameter name */
|
||||
String *value = Getvalue(p); /* Get parameter value */
|
||||
...
|
||||
do whatever
|
||||
...
|
||||
}
|
||||
|
||||
4. Typemaps
|
||||
-----------
|
||||
|
||||
Typemaps more or less work. However, the interface has changed slightly. Instead of
|
||||
|
||||
typemap_lookup("in","python",type,pname,"$source","$target",wrapper);
|
||||
|
||||
the function is
|
||||
|
||||
Swig_typemap_lookup("in",type,pname,"$source","$target",wrapper);
|
||||
|
||||
There are a variety of other changes to typemaps (see CHANGES).
|
||||
|
||||
5. Use of new types
|
||||
-------------------
|
||||
When possible, language modules should try to use the built in String,
|
||||
List, and Hash objects instead of C arrays or 'char *'. This will probably require a
|
||||
detailed pass through the code with an eye towards cleanup.
|
||||
|
||||
6. Miscellaneous
|
||||
----------------
|
||||
Language modules no longer need to concern themselves with formatting the
|
||||
wrapper code they produce (provided you are using the special Wrapper object).
|
||||
The function Wrapper_print() passes everything through a pretty-printer that
|
||||
automatically performs indentation and tries to clean things up. This especially
|
||||
works well when there are lots of typemaps.
|
||||
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>SWIG Parameter Handling</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<center>
|
||||
<h1>SWIG Parameter Handling</h1>
|
||||
|
||||
<p>
|
||||
David M. Beazley <br>
|
||||
dave-swig@dabeaz.com<br>
|
||||
January 9, 2007<br>
|
||||
|
||||
</b>
|
||||
</center>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
This document describes the functions related to management of function parameters and parameter lists in the SWIG core. These functions are declared in <tt>Source/Swig/swigparm.h</tt>. This API is considered to be stable.
|
||||
|
||||
<h2>Parameters</h2>
|
||||
|
||||
The following utility functions are used to create and copy individual parameters. In their most basic form, a parameter merely contains a type, a name, and an optional default value.
|
||||
|
||||
<p>
|
||||
<b><tt>Parm *NewParm(SwigType *type, const String_or_char *name)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Creates a new parameter object with type <tt>type</tt> and name <tt>name</tt>. The type is stored in the attribute "type" and the name is stored in the attribute "name".
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>Parm *CopyParm(Parm *p)</tt></b>
|
||||
<blockquote>
|
||||
Copies a parameter object. All string attributes are copied in the
|
||||
process of making the copy. However, no complex attributes (lists,
|
||||
hashes, etc.) are copied.
|
||||
</blockquote>
|
||||
|
||||
<h2>Parameter Lists</h2>
|
||||
|
||||
<p>
|
||||
<b><tt>ParmList *CopyParmList(ParmList *p)</tt></b>
|
||||
<blockquote>
|
||||
Creates a copy of a parameter list. A parameter list is merely a linked list of parameters created by NewParm().
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>ParmList *CopyParmListMax(ParmList *p, int count)</tt></b>
|
||||
<blockquote>
|
||||
Copies at most <tt>count</tt> parameters from the parameter list <tt>p</tt>.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>int ParmList_len(ParmList *p)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Returns the total number of parameters in a parameter list.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>int ParmList_numrequired(ParmList *p)</tt></b>
|
||||
<blockquote>
|
||||
Returns the number of required parameters in a parameter list. This pertains to invoking a function/method in C/C++.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>int ParmList_has_defaultargs(ParmList *p)</tt></b>
|
||||
<blockquote>
|
||||
Returns 1 if the parameter list has any default arguments. Otherwise returns 0.
|
||||
</blockquote>
|
||||
|
||||
|
||||
<h2>Code Generation Functions</h2>
|
||||
|
||||
<p>
|
||||
<b><tt>String *ParmList_str(ParmList *p)</tt></b>
|
||||
<blockquote>
|
||||
Creates a C prototype string of the parameters, but without any default values.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>String *ParmList_str_defaultargs(ParmList *p)</tt></b>
|
||||
<blockquote>
|
||||
Creates a C prototype string of the parameters and includes the default values (if any).
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>String *ParmList_protostr(ParmList *p)</tt></b>
|
||||
<blockquote>
|
||||
Creates a C prototype string of the parameters.
|
||||
</blockquote>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,341 @@
|
|||
|
||||
|
||||
|
||||
|
||||
Project Plan
|
||||
============
|
||||
SWIG Code Comments
|
||||
Google Summer of Code 2012
|
||||
|
||||
|
||||
This document describes goals for the Google Summer of Code 2012,
|
||||
SWIG code documentation project.
|
||||
|
||||
Author: Marko Klopcic, Dmitry Kabak
|
||||
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
The goal of this project is _not_ to translate _any_ possible Doxygen
|
||||
formatted comment to JavaDoc or PyDoc, but to make it possible to
|
||||
translate a subset of comment types in C/C++ code to
|
||||
JavaDoc and PyDoc. Covering all the Doxygen functionality would be to
|
||||
complex for the limited time. However, the code must be flexible so
|
||||
that implementing missing features would not require redesign of the
|
||||
comment handling code in SWIG.
|
||||
|
||||
There will also be a possibility to add untranslated comments to Java
|
||||
and Python code (## comments, see Doxygen manual), if the user will
|
||||
prefer to use Doxygen on the generated code.
|
||||
|
||||
Note:
|
||||
'-OK-' tick below means that the item is implemented, committed and
|
||||
working.
|
||||
|
||||
Abbreviations:
|
||||
JD - JavaDoc
|
||||
PD - PyDoc
|
||||
|
||||
|
||||
Functionality
|
||||
=============
|
||||
|
||||
Types of comments
|
||||
-----------------
|
||||
|
||||
Note:
|
||||
See 'http://www.stack.nl/~dimitri/doxygen/docblocks.html' for
|
||||
the detailed description of Doxygen syntax and terms used in this
|
||||
section.
|
||||
|
||||
1. -OK- Only JavaDoc (/** */) and Qt (/*! */) styles of comment blocks
|
||||
will be supported by SWIG translator.
|
||||
|
||||
2. -OK- The following doc after members will be supported:
|
||||
|
||||
int var; ///< Detailed description after the member
|
||||
//!<
|
||||
|
||||
int var; //!< Brief description after the member
|
||||
|
||||
int var; ///< Brief description after the member
|
||||
|
||||
|
||||
3. -OK- Only comments before or after declaration/definition will be
|
||||
supported. Comments with structural commands will be ignored
|
||||
(warning will be written). (What about writing them to
|
||||
'package.info.java' for JD?)
|
||||
|
||||
|
||||
Tags
|
||||
----
|
||||
|
||||
This section contains all doxygen tags taken from
|
||||
http://www.stack.nl/~dimitri/doxygen/commands.html. If a tag is
|
||||
marked as 'ignored', then the tag is ignored, but the text is copied
|
||||
to the destination documentation. 'Not implemented' means that the
|
||||
tag with it's contents is stripped out of the output.
|
||||
|
||||
Doxygen tags:
|
||||
|
||||
All tags: -OK-
|
||||
|
||||
\a - translated to <i></i> in JD, surrounded with _ in PD
|
||||
\addindex - ignored
|
||||
\addtogroup - ignored
|
||||
\anchor - ignored, not supported by JD and PD
|
||||
\arg - equivalent to \li
|
||||
\attention - ignored
|
||||
\authors, \author - translated to @author in JD, 'Author:' in PD
|
||||
\b - <b></b> in JD, surrounded with __ in PD
|
||||
\brief - ignored
|
||||
\bug - ignored
|
||||
\c - translated to <code></code> in JD, ignored in PD
|
||||
\callgraph - ignored, not supported by JD and PD
|
||||
\callergraph - ignored, not supported by JD and PD
|
||||
\category - ignored, used only in Objective C
|
||||
\cite - translated to <i></i> in JD, single quotes in PD
|
||||
\class - ignored (structural command)
|
||||
\code - translated to {@code ...} in JD, ignored in PD
|
||||
\cond - translated to 'Conditional comment: <condition>'. Later
|
||||
SWIG may support definitions of conditions in config file.
|
||||
\copybrief - ignored. Later SWIG may support this command by
|
||||
performing copy
|
||||
\copydetails - ignored. Later SWIG may support this command by
|
||||
performing copy
|
||||
\copydoc - ignored. Later SWIG may support this command by
|
||||
performing copy
|
||||
\copyright - replaced with text 'Copyright' in PD and PD
|
||||
\date - ignored
|
||||
\def - ignored (structural command)
|
||||
\defgroup - not supported
|
||||
\deprecated - translated to @deprecated in JD, 'Deprecated:' in PD
|
||||
\details - ignored
|
||||
\dir - not supported
|
||||
\dontinclude - not supported
|
||||
\dot - not supported. Later SWIG may call dot and produce the graph image
|
||||
to include in JD and PD
|
||||
\dotfile - see note for \dot
|
||||
\e - equivalent \a
|
||||
\else - see note for \cond
|
||||
\elseif - see note for \cond
|
||||
\em - equivalent to \a
|
||||
\endcode - see note for \code
|
||||
\endcond - translated to 'End of conditional comment: <condition>'. Later
|
||||
SWIG may support definitions of conditions in config file.
|
||||
\enddot - see note for \dot
|
||||
\endhtmlonly - ignored
|
||||
\endif - see note for \cond
|
||||
\endinternal - ignored
|
||||
\endlatexonly - ignored
|
||||
\endlink - see note for \link
|
||||
\endmanonly - ignored
|
||||
\endmsc - see note for \msc
|
||||
\endrtfonly - ignored
|
||||
\endverbatim - see note for \verbatim
|
||||
\endxmlonly - ignored
|
||||
\enum - ignored (structural command)
|
||||
\example - translated to 'Example:' in JD and PD
|
||||
\exception - equivalent to throws, but translates to @exception in JD
|
||||
\extends - not supported
|
||||
\f$ - ignored. Later swig may call LATeX to produce bitmaps with formulas
|
||||
to include in JD and PD
|
||||
\f[ - see note for \f$
|
||||
\f] - see note for \f$
|
||||
\f{ - see note for \f$
|
||||
\f} - see note for \f$
|
||||
\file - ignored (structural command)
|
||||
\fn - ignored (structural command)
|
||||
\headerfile - not supported
|
||||
\hideinitializer - not supported
|
||||
\htmlinclude - not supported
|
||||
\htmlonly - ignored
|
||||
\if - see note for \cond
|
||||
\ifnot - see note for \cond
|
||||
\image - translated to <img/> in JD only when target=HTML, translated to
|
||||
'Image: filename(Title)'
|
||||
\implements - not supported
|
||||
\include - not supported
|
||||
\includelineno - not supported
|
||||
\ingroup - not supported. Later swig may print group names as plain text
|
||||
in comments like 'Code group: something' in both JD and PD
|
||||
\internal - ignored
|
||||
\invariant - ignored
|
||||
\interface - ignored (structural command)
|
||||
\latexonly - ignored
|
||||
\li - trabslated to <li></li> in JD, ignored in PD
|
||||
\line - not supported
|
||||
\link - translated to {@link ...} in JD, ignored in PD
|
||||
\mainpage - ignored
|
||||
\manonly - ignored
|
||||
\memberof - not supported
|
||||
\msc - not supported. Later SWIG may call dot and produce the graph image
|
||||
to include in JD and PD
|
||||
\mscfile - see note for \msc
|
||||
\n - prints the new line
|
||||
\name - ignored
|
||||
\namespace - included in package-info.java if nspace feature is enabled,
|
||||
otherwise ignored, ignored in PD
|
||||
\nosubgrouping - ignored
|
||||
\note - translated to 'Note:' in both JD and PD
|
||||
\overload - prints 'This is an overloaded member function, provided for
|
||||
convenience. It differs from the above function only in what
|
||||
argument(s) it accepts.' to the output in both JD and PD
|
||||
\p - equivalent to \c
|
||||
\package - is kept same in JD (it is already a JD tag), ignored in PD
|
||||
\page - ignored
|
||||
\par - translated to <p alt='title'></p> in JD, 'Title: ...' in PD
|
||||
\paragraph - ignored
|
||||
\param - translated to @param in JD, special formatting in PD
|
||||
\post - ignored
|
||||
\pre - ignored
|
||||
\private - ignored
|
||||
\privatesection - ignored
|
||||
\property - ignored
|
||||
\protected - ignored
|
||||
\protectedsection - ignored
|
||||
\protocol - ignored (Objective-C tag)
|
||||
\public - ignored
|
||||
\publicsection - ignored
|
||||
\ref - ignored, not supported by JD and PD
|
||||
\related - ignored
|
||||
\relates - ignored
|
||||
\relatedalso - ignored
|
||||
\relatesalso - ignored
|
||||
\remark - translated to 'Remarks:' in both JD and PD
|
||||
\remarks - equivalent to remark
|
||||
\result - translated to @return in JD, 'Return:' in PD
|
||||
\return - equivalent to result
|
||||
\returns - equivalent to result
|
||||
\retval - ignored
|
||||
\rtfonly - ignored
|
||||
\sa - translated to @see in JD, 'See also:' in PD
|
||||
\section - not supported
|
||||
\see - equivalent to \sa
|
||||
\short - equivalent to \brief
|
||||
\showinitializer - not supported
|
||||
\since - translated to @since in JD, 'Since:' in PD
|
||||
\skip - not supported
|
||||
\skipline - not supported
|
||||
\snippet - not supported
|
||||
\struct - ignored (structural command)
|
||||
\subpage - not supported
|
||||
\subsection - not supported
|
||||
\subsubsection - not supported
|
||||
\tableofcontents - not supported
|
||||
\test - ignored
|
||||
\throw - translated to @throws in JD, 'Throws:' in PD
|
||||
\throws - equivalent to \throw
|
||||
\todo - translated to 'TODO:' in both JD and PD
|
||||
\tparam - similar to \arg
|
||||
\typedef - ignored (structural command)
|
||||
\union - ignored (structural command)
|
||||
\until - not supported
|
||||
\var - ignored (structural command)
|
||||
\verbatim - translated to {@literal ...} in JD, ignored in PD
|
||||
\verbinclude - ignored
|
||||
\version - translated to @version in JD, 'Version:' in PD
|
||||
\warning - translated to 'Warning:' in both JD and PD
|
||||
\weakgroup - not supported
|
||||
\xmlonly - ignored
|
||||
\xrefitem - ignored
|
||||
\$ - this and all the others below: these commands insert single char,
|
||||
it is escaped as HTML char in JD, kept as-is in PD
|
||||
\@
|
||||
\\
|
||||
\&
|
||||
\~
|
||||
\<
|
||||
\>
|
||||
\#
|
||||
\%
|
||||
\"
|
||||
\.
|
||||
\::
|
||||
|
||||
Optional functionality
|
||||
======================
|
||||
|
||||
That section describes some complex cases where the current code
|
||||
does not behave really well. Like a short to-do list of special cases.
|
||||
|
||||
-OK- When translating functions with default parameters in swig to
|
||||
java, it creates overloaded functions with all the parameters
|
||||
except the default ones. We need to copy the doxygen comment to
|
||||
such functions and correct the list of @param tags.
|
||||
|
||||
-OK- In doxygen there is a special tags (and even a special option)
|
||||
to create links to some code members from the current comment.
|
||||
Sometimes it needs a type of parameters specified because of the
|
||||
overloaded functions. And the same linking tags are supported in JD,
|
||||
but it has a completely different typesystem, so we need to translate
|
||||
the types of function parameters in comments also. For example:
|
||||
{@link MyClass#doSomething(const std::string &)}
|
||||
does not make sense in Java, so the type should be converted.
|
||||
{@link MyClass#doSomething(String)}
|
||||
|
||||
|
||||
Tests
|
||||
=====
|
||||
|
||||
The following test cases will be implemented:
|
||||
|
||||
-OK- Class comments.
|
||||
|
||||
-OK- Struct comments.
|
||||
-OK- Enum comments.
|
||||
-OK- Function comments.
|
||||
-OK- Var comments.
|
||||
|
||||
-OK- Class attributes, comment before and after declaration.
|
||||
-OK- Class methods, comment of parameters in function
|
||||
comment.
|
||||
-OK- Class methods, comment of parameters
|
||||
after parameter declaration.
|
||||
|
||||
-OK- Struct attributes, comment before and after declaration.
|
||||
-OK- Struct methods, comment of parameters in function
|
||||
comment.
|
||||
-OK- Struct methods, comment of parameters
|
||||
after parameter declaration.
|
||||
|
||||
-OK- Enum items JD and Qt style, comment before items
|
||||
-OK- Enum items JD and Qt style, comment after items
|
||||
|
||||
-OK- Class comment, with all supported tags.
|
||||
-OK- Class comment, with all doxygen tags, including
|
||||
ignored ones.
|
||||
|
||||
The list of all tests, in form of shell commands to make it simple
|
||||
to test project by copying the text below into terminal program.
|
||||
make doxygen_parsing.cpptest -s
|
||||
make doxygen_translate.cpptest -s
|
||||
make doxygen_translate_all_tags.cpptest -s
|
||||
make doxygen_basic_translate.cpptest -s
|
||||
make doxygen_basic_notranslate.cpptest -s
|
||||
make doxygen_translate_links.cpptest -s
|
||||
make doxygen_tricky_constructs.cpptest -s
|
||||
|
||||
|
||||
Refactoring
|
||||
===========
|
||||
|
||||
All the code in directory _Doxygen_ should be refactored:
|
||||
-OK- all methods should be class members
|
||||
-OK- most static methods should be normal members
|
||||
-OK- replace C arrays of strings and sequential searches with STL data
|
||||
structures and algorithms.
|
||||
-OK- use singletons instead of class instantiaion for each comment found.
|
||||
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
SWIG documentation will contain:
|
||||
-OK- command line options
|
||||
-OK- list of implemented features (types and placements of comments)
|
||||
-OK- list of unimplemented features (types and placements of comments)
|
||||
-OK- list of tags and their translations (all Doxygen tags).
|
||||
-OK- some amount of debugging and development information
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
This file describes the necessary functions and interfaces a language module
|
||||
needs to implement to take advantage of the run time type system. I assume you
|
||||
have read the run-time section of the Typemaps chapter in the SWIG
|
||||
documentation.
|
||||
|
||||
Last updated: February 23, 2005
|
||||
|
||||
The file we are concerned with here should be named langrun.swg. A good example
|
||||
of a simple file is the Lib/mzscheme/mzrun.swg file. First, a few requirements
|
||||
and notes:
|
||||
|
||||
1) Every function in this file should be declared static.
|
||||
|
||||
2) It should be inserted into the runtime section of the _wrap file from your
|
||||
config file. The Lib/swigrun.swg file should be included before this file.
|
||||
That is, you need to have
|
||||
%runtime "swigrun.swg"
|
||||
%runtime "langrun.swg"
|
||||
|
||||
3) You must also include the swiginit.swg file in the init section of the
|
||||
wrapper. That is, you should have
|
||||
%insert(init) "swiginit.swg"
|
||||
|
||||
4) From module.cxx, you need to call the SwigType_emit_type_table function, as
|
||||
well as register types with SwigType_remember or SwigType_remember_clientdata
|
||||
|
||||
5) By convention, all functions in this file are of the form
|
||||
SWIG_Language_Whatever, and #defines are used to rename SWIG API functions to
|
||||
these function names
|
||||
|
||||
6) You need to call void SWIG_InitializeModule(void *clientdata) from your init
|
||||
function.
|
||||
|
||||
7) You need to implement the runtimeCode() and defaultExternalRuntimeFilename()
|
||||
functions inside module.cxx. runtimeCode should return all the language
|
||||
specific runtime code as a string, and defaultExternalRuntimeFilename should
|
||||
return a string for the default name of the external runtime header. This is
|
||||
usually "swigpyrun.h", where "py" is replaced by the language name. These
|
||||
two functions are used by the -external-runtime argument.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Required Functions
|
||||
-------------------------------------------------------------------------------
|
||||
swig_module_info *SWIG_GetModule(void *clientdata);
|
||||
void SWIG_SetModule(void *clientdata, swig_module_info *mod);
|
||||
|
||||
The SetModule function should store the mod argument into some globally
|
||||
accessible variable in the target language. The action of these two functions
|
||||
is to provide a way for multiple modules to share information. The SetModule
|
||||
function should create a new global var named something like
|
||||
"swig_runtime_data_type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME
|
||||
SWIG_RUNTIME_VERSION is currently defined as "2", and SWIG_TYPE_TABLE_NAME is
|
||||
defined by the -DSWIG_TYPE_TABLE=mytable option when compiling the wrapper.
|
||||
|
||||
Alternatively, if the language supports modules, a module named
|
||||
"swig_runtime_data" SWIG_RUNTIME_VERSION can be created, and a global variable
|
||||
named "type_table" SWIG_TYPE_TABLE_NAME can be created inside it. The most
|
||||
common approach is to store the mod pointer in some global variable in the
|
||||
target language, but if the language provides an alternative place to store data
|
||||
then that is good too.
|
||||
|
||||
The way the code is set up, SetModule should only be called when GetModule
|
||||
returns NULL, and if SetModule is called a second time, the behavior is
|
||||
undefined. Just make sure it doesn't crash in the random chance occurrence that
|
||||
SetModule is called twice.
|
||||
|
||||
There are two options here.
|
||||
|
||||
1) The preferred approach is for GetModule and SetModule to not require a
|
||||
clientdata pointer. If you can at all avoid it, please do so. Here, you would
|
||||
write swig_module_info *SWIG_Language_GetModule();
|
||||
void SWIG_Language_SetModule(swig_module_info *mod);
|
||||
and then add
|
||||
#define SWIG_GetModule(clientdata) SWIG_Language_GetModule()
|
||||
#define SWIG_SetModule(cd, ptr) SWIG_Language_SetModule(ptr)
|
||||
You would then call
|
||||
SWIG_InitializeModule(0)
|
||||
|
||||
2) If GetModule and SetModule need to take a custom pointer (most notably an
|
||||
environment pointer, see tcl or mzscheme), then you should write
|
||||
swig_module_info *SWIG_Language_GetModule(void *clientdata)
|
||||
void SWIG_Language_SetModule(void *clientdata, swig_module_info *mod);
|
||||
and also define
|
||||
#define SWIG_GetModule(cd) SWIG_Language_GetModule(cd)
|
||||
#define SWIG_SetModule(cd, ptr) SWIG_Language_SetModule(cd, ptr)
|
||||
#define SWIG_MODULE_CLIENTDATA_TYPE Whatever
|
||||
SWIG_MODULE_CLIENTDATA_TYPE should be defined to whatever the type of
|
||||
clientdata is.
|
||||
|
||||
You would then call SWIG_InitializeModule(clientdata), and clientdata would get
|
||||
passed to GetModule and SetModule. clientdata will not be stored and will only
|
||||
be referenced during the InitializeModule call. After InitializeModule returns,
|
||||
clientdata does not need to be valid any more.
|
||||
|
||||
This method is not preferred, because it makes external access to the type
|
||||
system more complicated. See the Modules chapter of the documentation, and read
|
||||
the "External access to the run-time" section. Then take a look at
|
||||
Lib/runtime.swg. Anybody that calls SWIG_TypeQuery needs to pass along the
|
||||
clientdata pointer, and that is the reason for defining
|
||||
SWIG_MODULE_CLIENTDATA_TYPE.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Standard Functions
|
||||
-------------------------------------------------------------------------------
|
||||
These functions are not required and their API is not formalized, but almost all
|
||||
language modules implement them for consistency across languages. Throughout
|
||||
this discussion, I will use LangType to represent the underlying language type
|
||||
(Scheme_Object * in mzscheme, PyObject * in python, etc)
|
||||
|
||||
|
||||
|
||||
LangObj SWIG_NewPointerObj(void *ptr, swig_type_info *type, int flags);
|
||||
Create and return a new pointer object that has both ptr and type. For almost
|
||||
all language modules, flags is used for ownership. If flags==1, then the
|
||||
created pointer should be registered to be garbage collected.
|
||||
|
||||
|
||||
|
||||
int SWIG_ConvertPtr(LangType obj, void **result, swig_type_info *type, int flags);
|
||||
Convert a language wrapped pointer into a void *. The pointer is returned in
|
||||
result, and the function should return 0 on success, non-zero on error.
|
||||
A sample ConvertPtr is given here:
|
||||
|
||||
swig_cast_info *cast;
|
||||
|
||||
if (<obj is a wrapped pointer type>) {
|
||||
cast = SWIG_TypeCheck(<obj type name>, type);
|
||||
cast = SWIG_TypeCheckStruct(<obj type structure>, type);
|
||||
if (cast) {
|
||||
*result = SWIG_TypeCast(cast, <obj pointer>);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
|
||||
Either TypeCheck or TypeCheckStruct can be called, depending on how the pointer
|
||||
is wrapped in langtype. If obj stores the void pointer and the type name, then
|
||||
the TypeCheck function should be used, while if obj stores the void pointer and
|
||||
a pointer to the swig_type_info structure, then the TypeCheckStruct function
|
||||
should be called. The TypeCheckStruct is slightly faster, since it does a
|
||||
pointer comparison instead of a strcmp.
|
||||
|
||||
The flag argument to ConvertPtr is used in some languages for disowning a
|
||||
pointer. If the wrapped C function is taking ownership of the pointer (that
|
||||
means, the wrapped C function is responsible for deleting the object), then that
|
||||
pointer should be removed from the garbage collector. We do that in the
|
||||
ConvertPtr function. The pointer is still valid in the target language, but
|
||||
when the target language type is garbage collected, it will not call the
|
||||
associated destructor. Languages have a special typemap called DISOWN that can be
|
||||
applied which passes this argument. All the languages have the flags argument
|
||||
for consistency, and the flags argument can be ignored or used for some other
|
||||
purpose.
|
||||
|
||||
|
||||
void *SWIG_MustGetPtr(LangType obj, swig_type_info *type, int flags,
|
||||
int argnum, const char *func_name) {
|
||||
void *result;
|
||||
if (SWIG_ConvertPtr(s, &result, type, flags)) {
|
||||
generate runtime type error ("Error in func_name, expected a" +
|
||||
type->str ? type->str : "void *" +
|
||||
"at argument number" + argnum);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
This function is optional, and the number and type of parameters can be
|
||||
different, but is useful for typemap purposes:
|
||||
%typemap(in) SWIGTYPE *, SWIGTYPE &, SWIGTYPE [] {
|
||||
$1 = ($1_ltype)SWIG_MustGetPtr($input, $descriptor, 0, $argnum, FUNC_NAME);
|
||||
}
|
|
@ -0,0 +1,283 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>SWIG C Scanner</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<center>
|
||||
<h1>SWIG C/C++ Scanning</h1>
|
||||
|
||||
<p>
|
||||
David M. Beazley <br>
|
||||
dave-swig@dabeaz.com<br>
|
||||
January 11, 2007<br>
|
||||
|
||||
</b>
|
||||
</center>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
This document describes functions that can be used to tokenize C/C++
|
||||
input text. These functions are relatively low-level and are meant to
|
||||
be used in the implementation of scanners that can be plugged into yacc or used for
|
||||
other purposes. For instance, the preprocessor uses these functions to evaluate and test
|
||||
constant expressions.
|
||||
|
||||
<p>
|
||||
All of these functions are declared in <tt>Source/Swig/swigscan.h</tt>. This API is considered to be stable.
|
||||
|
||||
<h2>Creation and Deletion of Scanners</h2>
|
||||
|
||||
The following functions are used to create and destroy a scanner object. More than one scanner object can be created and used
|
||||
as necessary.
|
||||
|
||||
<p>
|
||||
<b><tt>Scanner *NewScanner()</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Creates a new scanner object. The scanner contains initially contains no text. To feed text to the scanner use <tt>Scanner_push()</tt>.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>Scanner *DelScanner()</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Deletes a scanner object.
|
||||
</blockquote>
|
||||
|
||||
<h2>Scanner Functions</h2>
|
||||
|
||||
<p>
|
||||
<b><tt>void Scanner_clear(Scanner *s)</tt></b>
|
||||
<blockquote>
|
||||
Clears all text from the scanner. This can be used to reset a scanner to its initial state, ready to receive new input text.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void Scanner_push(Scanner *s, String *text)</tt></b>
|
||||
<blockquote>
|
||||
Pushes an input string into the scanner. Subsequent tokens will be
|
||||
returned from the new string. If the scanner is already processing a
|
||||
string, the pushed string takes precedence--in effect, interrupting
|
||||
the scanning of the previous string. This behavior is used to
|
||||
implement certain SWIG features such as the <tt>%inline</tt>
|
||||
directive. Once the pushed string has been completely scanned, the
|
||||
scanner will return to scanning the previous string (if any). The
|
||||
scanning of text relies upon the DOH file interface to strings
|
||||
(<tt>Getc()</tt>, <tt>Ungetc()</tt>, etc.). Prior to calling this
|
||||
function, the input string should be set so that its file pointer is
|
||||
in the location where you want scanning to begin. You may have to
|
||||
use <tt>Seek()</tt> to set the file pointer back to the beginning of a
|
||||
string prior to using this function.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void Scanner_pushtoken(Scanner *s, int tokvalue, String_or_char *val)</tt></b>
|
||||
<blockquote>
|
||||
Pushes a token into the scanner. This exact token will be returned by the next call to <tt>Scanner_token()</tt>.
|
||||
<tt>tokvalue</tt> is the integer token value to return and <tt>val</tt> is the token text to return. This
|
||||
function is only used to handle very special parsing cases. For instance, if you need the scanner to
|
||||
return a fictitious token into order to enter a special parsing case.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>int Scanner_token(Scanner *s)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Returns the next token. An integer token code is returned (see table below) on success. If no more input text is
|
||||
available 0 is returned. If a scanning error occurred, -1 is returned. In this case, error information can be
|
||||
obtained using <tt>Scanner_errinfo()</tt>.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>String *Scanner_text(Scanner *s)</tt></b>
|
||||
<blockquote>
|
||||
Returns the scanned text corresponding to the last token returned by <tt>Scanner_token()</tt>. The returned string
|
||||
is only valid until the next call to <tt>Scanner_token()</tt>. If you need to save it, make a copy.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void Scanner_skip_line(Scanner *s)</tt></b>
|
||||
<blockquote>
|
||||
Skips to the end of the current line. The text skipped can be obtained using <tt>Scanner_text()</tt> afterwards.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void Scanner_skip_balanced(Scanner *s, int startchar, int endchar)</tt></b>
|
||||
<blockquote>
|
||||
Skips to the end of a block of text denoted by starting and ending characters. For example, <tt>{</tt> and <tt>}</tt>. The
|
||||
function is smart about how it skips text. String literals and comments are ignored. The function also is aware of nesting. The
|
||||
skipped text can be obtained using <tt>Scanner_text()</tt> afterwards. Returns 0 on success, -1 if no matching <tt>endchar</tt> could be found.
|
||||
</blockquote>
|
||||
|
||||
|
||||
<p>
|
||||
<b><tt>void Scanner_set_location(Scanner *s, int startchar, int endchar)</tt></b>
|
||||
<blockquote>
|
||||
Changes the current filename and line number of the scanner.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>String *Scanner_file(Scanner *s)</tt></b>
|
||||
<blockquote>
|
||||
Gets the current filename associated with text in the scanner.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>int Scanner_line(Scanner *s)</tt></b>
|
||||
<blockquote>
|
||||
Gets the current line number associated with text in the scanner.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>int Scanner_start_line(Scanner *s)</tt></b>
|
||||
<blockquote>
|
||||
Gets the starting line number of the last token returned by the scanner.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void Scanner_idstart(Scanner *s, char *idchar)</tt></b>
|
||||
<blockquote>
|
||||
Sets additional characters (other than the C default) that may be used to start C identifiers. <tt>idchar</tt> is a string
|
||||
containing the characters (e.g., "%@"). The purpose of this function is to up special keywords such as "%module" or "@directive" as
|
||||
simple identifiers.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>String *Scanner_errmsg(Scanner *s)</tt></b>
|
||||
<blockquote>
|
||||
Returns the error message associated with the last scanner error (if any). This will only return a meaningful result
|
||||
if <tt>Scanner_token()</tt> returned -1.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>int Scanner_errline(Scanner *s)</tt></b>
|
||||
<blockquote>
|
||||
Returns the line number associated with the last scanner error (if any). This will only return a meaningful result
|
||||
if <tt>Scanner_token()</tt> returned -1. The line number usually corresponds to the starting line number of a particular
|
||||
token (e.g., for unterminated strings, comments, etc.).
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>int Scanner_isoperator(int tokval)</tt></b>
|
||||
<blockquote>
|
||||
A convenience function that returns 0 or 1 depending on whether <tt>tokval</tt> is a valid C/C++ operator (i.e., a candidate for
|
||||
operator overloading).
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void Scanner_freeze_line(int val)</tt></b>
|
||||
<blockquote>
|
||||
Freezes the current line number depending upon whether or not <tt>val</tt> is 1 or 0. When the line number is frozen, newline characters will not result in
|
||||
updates to the line number. This is sometimes useful in tracking line numbers through complicated macro expansions.
|
||||
</blockquote>
|
||||
|
||||
|
||||
<h2>Token Codes</h2>
|
||||
|
||||
The following table shows token codes returned by the scanner. These are integer codes returned by
|
||||
the <tt>Scanner_token()</tt> function.
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
Token code C Token
|
||||
------------------------- -------------
|
||||
SWIG_TOKEN_LPAREN (
|
||||
SWIG_TOKEN_RPAREN )
|
||||
SWIG_TOKEN_SEMI ;
|
||||
SWIG_TOKEN_COMMA ,
|
||||
SWIG_TOKEN_STAR *
|
||||
SWIG_TOKEN_TIMES *
|
||||
SWIG_TOKEN_LBRACE {
|
||||
SWIG_TOKEN_RBRACE }
|
||||
SWIG_TOKEN_EQUAL =
|
||||
SWIG_TOKEN_EQUALTO ==
|
||||
SWIG_TOKEN_NOTEQUAL !=
|
||||
SWIG_TOKEN_PLUS +
|
||||
SWIG_TOKEN_MINUS -
|
||||
SWIG_TOKEN_AND &
|
||||
SWIG_TOKEN_LAND &&
|
||||
SWIG_TOKEN_OR |
|
||||
SWIG_TOKEN_LOR ||
|
||||
SWIG_TOKEN_XOR ^
|
||||
SWIG_TOKEN_LESSTHAN <
|
||||
SWIG_TOKEN_GREATERTHAN >
|
||||
SWIG_TOKEN_LTEQUAL <=
|
||||
SWIG_TOKEN_GTEQUAL >=
|
||||
SWIG_TOKEN_NOT ~
|
||||
SWIG_TOKEN_LNOT !
|
||||
SWIG_TOKEN_LBRACKET [
|
||||
SWIG_TOKEN_RBRACKET ]
|
||||
SWIG_TOKEN_SLASH /
|
||||
SWIG_TOKEN_DIVIDE /
|
||||
SWIG_TOKEN_BACKSLASH \
|
||||
SWIG_TOKEN_POUND #
|
||||
SWIG_TOKEN_PERCENT %
|
||||
SWIG_TOKEN_MODULO %
|
||||
SWIG_TOKEN_COLON :
|
||||
SWIG_TOKEN_DCOLON ::
|
||||
SWIG_TOKEN_DCOLONSTAR ::*
|
||||
SWIG_TOKEN_LSHIFT <<
|
||||
SWIG_TOKEN_RSHIFT >>
|
||||
SWIG_TOKEN_QUESTION ?
|
||||
SWIG_TOKEN_PLUSPLUS ++
|
||||
SWIG_TOKEN_MINUSMINUS --
|
||||
SWIG_TOKEN_PLUSEQUAL +=
|
||||
SWIG_TOKEN_MINUSEQUAL -=
|
||||
SWIG_TOKEN_TIMESEQUAL *=
|
||||
SWIG_TOKEN_DIVEQUAL /=
|
||||
SWIG_TOKEN_ANDEQUAL &=
|
||||
SWIG_TOKEN_OREQUAL |=
|
||||
SWIG_TOKEN_XOREQUAL ^=
|
||||
SWIG_TOKEN_LSEQUAL <<=
|
||||
SWIG_TOKEN_RSEQUAL >>=
|
||||
SWIG_TOKEN_MODEQUAL %=
|
||||
SWIG_TOKEN_ARROW ->
|
||||
SWIG_TOKEN_ARROWSTAR ->*
|
||||
SWIG_TOKEN_PERIOD .
|
||||
SWIG_TOKEN_AT @
|
||||
SWIG_TOKEN_DOLLAR $
|
||||
SWIG_TOKEN_ENDLINE Literal newline
|
||||
SWIG_TOKEN_ID identifier
|
||||
SWIG_TOKEN_FLOAT Floating point with F suffix (e.g., 3.1415F)
|
||||
SWIG_TOKEN_DOUBLE Floating point (e.g., 3.1415 )
|
||||
SWIG_TOKEN_INT Integer (e.g., 314)
|
||||
SWIG_TOKEN_UINT Unsigned integer (e.g., 314U)
|
||||
SWIG_TOKEN_LONG Long integer (e.g., 314L)
|
||||
SWIG_TOKEN_ULONG Unsigned long integer (e.g., 314UL)
|
||||
SWIG_TOKEN_LONGLONG Long long integer (e.g., 314LL )
|
||||
SWIG_TOKEN_ULONGLONG Unsigned long long integer (e.g., 314ULL)
|
||||
SWIG_TOKEN_CHAR Character literal in single quotes ('c')
|
||||
SWIG_TOKEN_STRING String literal in double quotes ("str")
|
||||
SWIG_TOKEN_RSTRING Reverse quote string (`str`)
|
||||
SWIG_TOKEN_CODEBLOCK SWIG code literal block %{ ... %}
|
||||
SWIG_TOKEN_COMMENT C or C++ comment (// or /* ... */)
|
||||
SWIG_TOKEN_ILLEGAL Illegal character
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<b>Notes</b>
|
||||
|
||||
<ul>
|
||||
<li>When more than one token code exist for the same token text, those codes are identical (e.g., <tt>SWIG_TOKEN_STAR</tt> and <tt>SWIG_TOKEN_TIMES</tt>).
|
||||
|
||||
<p>
|
||||
<li>
|
||||
String literals are returned in their exact representation in which escape codes (if any) have been interpreted.
|
||||
|
||||
<p>
|
||||
<li>
|
||||
All C identifiers and keywords are simply returned as <tt>SWIG_TOKEN_ID</tt>. To check for specific keywords, you will need to
|
||||
add extra checking on the returned text.
|
||||
|
||||
<p>
|
||||
<li>C and C++ comments include the comment starting and ending text (e.g., "//", "/*").
|
||||
|
||||
<p>
|
||||
<li>The maximum token integer value is found in the constant <tt>SWIG_MAXTOKENS</tt>. This can be used if you wanted to create
|
||||
an array or table for the purposes of remapping tokens to a different set of codes. For instance, if you are
|
||||
using these functions to write a yacc-compatible lexer.
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,284 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>SWIG Parse Tree Handling</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<center>
|
||||
<h1>SWIG Parse Tree Handling</h1>
|
||||
</center>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
This document describes the functions related to the handling of
|
||||
parse trees in SWIG. The structure of SWIG parse trees has been influenced heavily by ideas
|
||||
from XML-DOM trees. In fact, the functions in the API and attribute names are nearly identical.
|
||||
The header file <tt>Source/swig/swigtree.h</tt> contains the functions and macros described in
|
||||
this document. This API is
|
||||
considered to be stable.
|
||||
|
||||
<h2>Parse tree navigation</h2>
|
||||
|
||||
The following macros are used to navigate the parse tree.
|
||||
|
||||
<p>
|
||||
<b><tt>nodeType(n)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Returns the type of a node as a String object. The type is stored in the "nodeType" attribute of <tt>n</tt>.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>parentNode(n)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Returns the parent of a node. This is found in the "parentNode" attribute of <tt>n</tt>.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>previousSibling(n)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Returns the previous sibling of a node (if any). This is found in the "previousSibling" attribute of <tt>n</tt>.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>nextSibling(n)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Returns the next sibling of a node (if any). This is found in the "nextSibling" attribute of <tt>n</tt>.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>firstChild(n)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Returns the first child of a node (if any). This is found in the "firstChild" attribute of <tt>n</tt>.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>lastChild(n)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Returns the last child of a node (if any). This is found in the "lastChild" attribute of <tt>n</tt>.
|
||||
</blockquote>
|
||||
|
||||
|
||||
<h2>Parse Tree Construction</h2>
|
||||
|
||||
The following macros are used to construct parse trees.
|
||||
|
||||
<p>
|
||||
<b><tt>set_nodeType(n, val)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Sets the nodeType attribute of n. val is a string containing the type.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>set_parentNode(n, parent)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Sets the parent of node n.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>set_previousSibling(n, prev)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Sets the previous sibling of node n.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>set_nextSibling(n, next)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Sets the next sibling of node n.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>set_firstChild(n, chd)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Sets the first child of node n.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>set_lastChild(n, chd)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Sets the last child of node n.
|
||||
</blockquote>
|
||||
|
||||
<h2>Tree Management Functions</h2>
|
||||
|
||||
The following functions are used to help with the management and construction of parse trees.
|
||||
|
||||
<p>
|
||||
<b><tt>void appendChild(Node *node, Node *child)</tt></b>
|
||||
<blockquote>
|
||||
Adds a new child to <tt>node</tt>. This function takes care of adjusting the "firstChild" and "lastChild" attributes of <tt>node</tt> to appropriate values. After calling this function, the "lastChild" attribute will point to <tt>child</tt>.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void prependChild(Node *node, Node *child)</tt></b>
|
||||
<blockquote>
|
||||
Prepends a new child to <tt>node</tt>. The new child is added so that it becomes the first child of <tt>node</tt>.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void removeNode(Node *node)</tt></b>
|
||||
<blockquote>
|
||||
Removes a node from the parse tree. The removal process detaches a node from its parent by removing it from the parent's child list. Upon return, <tt>node</tt> will have no parent and no siblings. This function does NOT delete <tt>node</tt> or modify children of <tt>node</tt>. If desired, <tt>node</tt> could be reattached to a different part of the parse tree.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>Node *copyNode(Node *node)</tt></b>
|
||||
<blockquote>
|
||||
Copies a node, but only copies those attributes that are simple strings. Thus, the new node will not contain any references to other nodes, lists, hashes, or other complex data structures. This function may be useful if you want to copy the data contents of a node in the process of creating a new parse tree node.
|
||||
</blockquote>
|
||||
|
||||
|
||||
<h2>Attribute Checking</h2>
|
||||
|
||||
The following utility is provided since this is an extremely common operation.
|
||||
|
||||
<p>
|
||||
<b><tt>int checkAttribute(Node *n, const String_or_char *name, const String_or_char *value)</tt></b>
|
||||
<blockquote>
|
||||
This function checks to see whether node <tt>n</tt> has a given
|
||||
attribute name and that the attribute has a given value. Returns 0 or
|
||||
1.
|
||||
</blockquote>
|
||||
|
||||
|
||||
<h2>Node Transformation</h2>
|
||||
|
||||
In the course of processing, SWIG often applies a transform to a node.
|
||||
This transformation process made modify many of the attributes--even
|
||||
changing the type of a node. The following functions are used to help
|
||||
manage this transformation process. In addition to provide sanity
|
||||
checks, they save the old contents of the node so that they can be
|
||||
restored later.
|
||||
|
||||
<p>
|
||||
<b><tt>void Swig_save(const char *namespace, Node *n, ...)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
This function takes a node and a list of attribute names and saves their contents in a specified namespace. For example,
|
||||
the call
|
||||
|
||||
<pre>
|
||||
Swig_save("temp",n,"type","parms","name",NIL)
|
||||
</pre>
|
||||
|
||||
takes the attributes "type","parms", and "name" and saves their
|
||||
contents under the attribute names "temp:type","temp:parms","temp:name". In addition, this function sets
|
||||
an attribute "view" to hold the name of the current namespace. In this example, the "view" attribute would be set
|
||||
to "temp". The attribute names specified are all optional. If one or more of the attributes don't exist,
|
||||
this function merely records that those attributes did not exist in the original node.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void Swig_require(const char *namespace, Node *n, ...)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
This function is similar to <tt>Swig_save()</tt> except that adds additional attribute checking. There are different interpretations
|
||||
of the attribute names. A name of "attr" merely requests that the function check for the presence of an attribute. If the attribute is missing, SWIG will exit with a failed assertion. An attribute name of "?attr" specifies that the attribute "attr" is optional and
|
||||
that its old value must be saved (if any). An attribute name of "*attr" specifies that the attribute is required and that
|
||||
its value must be saved. The saving of attributes is performed in the same manner as with <tt>Swig_save()</tt>. Here is an example:
|
||||
|
||||
<pre>
|
||||
Swig_require("temp",n,"type","*name","?parms",NIL);
|
||||
</pre>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void Swig_restore(Node *n)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
This function restores a node to the state it was in prior to the last <tt>Swig_save()</tt> or <tt>Swig_require()</tt> call. This is used to undo node transformations.
|
||||
</blockquote>
|
||||
|
||||
<h2>Debugging Functions</h2>
|
||||
|
||||
<p>
|
||||
The following functions can be used to help debug any SWIG DOH object.
|
||||
</p>
|
||||
|
||||
<b><tt>void Swig_print(DOH *object, int count = -1)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Prints to stdout a string representation of any DOH type.
|
||||
The number of nested Hash types to expand is set by count (default is 1 if count<0). See Swig_set_max_hash_expand() to change default.
|
||||
<pre>
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<b><tt>void Swig_print_with_location(DOH *object, int count = -1)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Prints to stdout a string representation of any DOH type, within [] brackets
|
||||
for Hash and List types, prefixed by line and file information.
|
||||
The number of nested Hash types to expand is set by count (default is 1 if count<0). See Swig_set_max_hash_expand() to change default.
|
||||
<pre>
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
|
||||
<p>
|
||||
The following functions can be used to help debug SWIG parse trees.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b><tt>void Swig_print_tags(Node *node, String_or_char *prefix)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Prints the tag-structure of the parse tree to standard output. <tt>node</tt> is the top-level parse tree node. <tt>prefix</tt> is
|
||||
a string prefix that's added to the start of each line. Normally, you would specify the empty string or NIL for <tt>prefix</tt>.
|
||||
This function is called by the <tt>-debug-tags</tt> option to SWIG.
|
||||
|
||||
<pre>
|
||||
% swig -debug-tags -python example.i
|
||||
. top (:1)
|
||||
. top . include (/Users/beazley/Projects/share/swig/1.3.31/swig.swg:0)
|
||||
. top . include . include (/Users/beazley/Projects/share/swig/1.3.31/swigwarnings.swg:0)
|
||||
. top . include . include . include (/Users/beazley/Projects/share/swig/1.3.31/swigwarn.swg:0)
|
||||
...
|
||||
...
|
||||
. top . include (example.i:0)
|
||||
. top . include . module (example.i:2)
|
||||
. top . include . insert (example.i:7)
|
||||
. top . include . cdecl (example.i:5)
|
||||
. top . include . cdecl (example.i:6)
|
||||
</pre>
|
||||
|
||||
Since many language modules include hundreds of typemaps and other information, the output of this can be significantly more complicated than you might expect.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void Swig_print_node(Node *node)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Prints the contents of a parse tree node, including all children, to standard output. The output includes all attributes
|
||||
and other details.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void Swig_print_tree(Node *node)</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Prints the same output as <tt>Swig_print_node()</tt> except that it also processes all of the siblings of <tt>node</tt>. This can
|
||||
be used to dump the entire parse tree to standard output. The command line options <tt>-debug-module</tt>
|
||||
and <tt>-debug-top</tt> use this function to display the parse tree for a SWIG input file.
|
||||
</blockquote>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Wrapper Objects</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<center>
|
||||
<h1>Wrapper Objects</h1>
|
||||
|
||||
<p>
|
||||
David M. Beazley <br>
|
||||
dave-swig@dabeaz.com<br>
|
||||
January 15, 2007<br>
|
||||
|
||||
</b>
|
||||
</center>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
This document describes the functions related to management of
|
||||
wrapper objects. A wrapper object is a low-level
|
||||
data structure used to contain the C/C++ code that is emitted during the
|
||||
wrapping process. It contains not only the emitted code, but information
|
||||
about local variables. These objects are a critical component of almost all
|
||||
SWIG target language modules.
|
||||
|
||||
<p>
|
||||
The functions described here are declared
|
||||
in <tt>Source/Swig/swigwrap.h</tt>. This API is considered to be
|
||||
stable.
|
||||
|
||||
<h2>Creating and Destroying Wrappers</h2>
|
||||
|
||||
The following functions create and destroy wrapper objects.
|
||||
|
||||
<p>
|
||||
<b><tt>Wrapper *NewWrapper()</tt></b>
|
||||
|
||||
<blockquote>
|
||||
Creates a new wrapper object.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void DelWrapper(Wrapper *w)</tt></b>
|
||||
<blockquote>
|
||||
Destroys a wrapper object.
|
||||
</blockquote>
|
||||
|
||||
<h2>Wrapper Objects</h2>
|
||||
|
||||
The <tt>Wrapper</tt> object returned by <tt>NewWrapper()</tt> has
|
||||
three public attributes.
|
||||
|
||||
<blockquote><pre>
|
||||
typedef struct Wrapper {
|
||||
String *def;
|
||||
String *locals;
|
||||
String *code;
|
||||
} Wrapper;
|
||||
</pre></blockquote>
|
||||
|
||||
The <tt>def</tt> attribute is a string that holds the function
|
||||
definition line. This line declares the function name, return type,
|
||||
and parameters. Language modules create this declaration by simply printing
|
||||
the appropriate text into this attribute.
|
||||
|
||||
<p>
|
||||
The <tt>locals</tt> attribute is a string that holds the code
|
||||
related to any local variables declaration. Normally, language modules
|
||||
do not emit code to this string directly. They use <tt>Wrapper_add_local()</tt> or <tt>Wrapper_new_local()</tt> to do this.
|
||||
|
||||
<p>
|
||||
The <tt>code</tt> attribute is a string that holds code related to the body of the function. Almost all code emitted by SWIG language modules is printed into this attribute.
|
||||
|
||||
<h2>Creating Local Variables</h2>
|
||||
|
||||
Perhaps the most useful aspect of <tt>Wrapper</tt> objects is the
|
||||
management of local variables. When creating a wrapper, it is often
|
||||
necessary to emit local variables related to the API of the target
|
||||
language. In addition to this, typemaps and other aspects of SWIG
|
||||
rely upon their own local variables. The following functions are used
|
||||
to create local variables, but also provide support for renaming
|
||||
variables in order to avoid name clashes.
|
||||
|
||||
<p>
|
||||
<b><tt>int Wrapper_add_local(Wrapper *w, const String_or_char *name, const String_or_char *decl)</tt></b>
|
||||
<blockquote>
|
||||
Adds a new local variable to the wrapper object. <tt>name</tt> is the
|
||||
name of the local variable. <tt>decl</tt> is a string containing the
|
||||
actual variable declaration code. For example, if you wanted to
|
||||
declare a variable "<tt>int x = 42;</tt>", you would set <tt>name</tt>
|
||||
to <tt>"x"</tt> and
|
||||
<tt>decl</tt> to <tt>"int x = 42;"</tt>. On success, the text in
|
||||
<tt>decl</tt> is added to the <tt>locals</tt> attribute of <tt>w</tt>
|
||||
and 0 is returned. -1 is returned if a variable with the given name
|
||||
has already been declared.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>int Wrapper_add_localv(Wrapper *w, const String_or_char *name, ...)</tt></b>
|
||||
<blockquote>
|
||||
The same as <tt>Wrapper_add_local()</tt> except that instead of
|
||||
passing a single string for the declaration, a NULL-terminated list of
|
||||
strings can be passed. These strings are joined together when
|
||||
producing the output. This convention turns out to be fairly useful
|
||||
since language modules often create their output into pieces.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>char * Wrapper_new_local(Wrapper *w, const String_or_char *name, const String_or_char *decl)</tt></b>
|
||||
<blockquote>
|
||||
The same as <tt>Wrapper_add_local()</tt> except that if a local variable
|
||||
with the given name already exists, this function picks a new name and adds
|
||||
the declaration using the new name. The actual name used for the variable
|
||||
is returned. This function is used when generating code originating from
|
||||
typemaps. For instance, if a typemap declares a local variable, that variable
|
||||
might have to be renamed if the same typemap is used more than once in the same function.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>char * Wrapper_new_localv(Wrapper *w, const String_or_char *name,...)</tt></b>
|
||||
<blockquote>
|
||||
The same as <tt>Wrapper_new_localv()</tt>, but accepts a NULL-terminated list
|
||||
of strings as code output.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>int Wrapper_check_local(Wrapper *w, const String_or_char *name)</tt></b>
|
||||
<blockquote>
|
||||
Checks to see if a local variable with name <tt>name</tt> has been declared. Returns 1 if the local is defined, 0 otherwise.
|
||||
</blockquote>
|
||||
|
||||
<h2>Output</h2>
|
||||
|
||||
<p>
|
||||
<b><tt>void Wrapper_print(Wrapper *w, File *f)</tt></b>
|
||||
<blockquote>
|
||||
This function is used to format a wrapper function for output. The
|
||||
formatted wrapper function is emitted to <tt>f</tt> which may be any
|
||||
file-like object including a <tt>FILE *</tt> object or a <tt>String
|
||||
*</tt> object. When emitting the wrapper, the code printed to the
|
||||
wrapper object is automatically formatted. By default, the formatting
|
||||
is done according to a "pretty printing" style in which lines are split onto
|
||||
multiple lines and indented according to reasonable C formatting rules. This produces code that is moderately readable should you want to look at the wrapper
|
||||
code output. An alternative output mode is "compact printing" in which
|
||||
lines are collected and compacted. This may result in multiple C statements
|
||||
appearing on the same line. This mode is sometimes used when the size of
|
||||
a wrapper file is too large for certain compilers. For example, some compilers
|
||||
might impose a limit of 65536 lines per source file.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void Wrapper_compact_print_mode_set(int flag)</tt></b>
|
||||
<blockquote>
|
||||
Sets the output mode of the <tt>Wrapper_print()</tt>
|
||||
function. If <tt>flag</tt> is set to 1, then wrapper code is formatted
|
||||
to be compact.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void Wrapper_pretty_print(String *str, File *f)</tt></b>
|
||||
<blockquote>
|
||||
Utility function that reformats a string containing C/C++ code and outputs
|
||||
it to the file-like object <tt>f</tt>. The formatting process indents the code
|
||||
and structures it according to reasonable C formatting rules.
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b><tt>void Wrapper_compact_print(String *str, File *f)</tt></b>
|
||||
<blockquote>
|
||||
Utility function that reformats a string containing C/C++ code and outputs
|
||||
it to the file-like object <tt>f</tt>. The formatting process tries to
|
||||
make the code as compact as possible, without going completely overboard. For
|
||||
example, multiple C statements may be combined onto a single line and braces may be aligned to not use up extra lines.
|
||||
</blockquote>
|
||||
|
||||
|
||||
<h2>An Example</h2>
|
||||
|
||||
Here is a simple example of how these functions are used. Suppose
|
||||
you wanted to emit the following C function:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
void foo(int n) {
|
||||
int i;
|
||||
for (i = 0; i < n; i++) {
|
||||
printf("%d\n", i);
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
Here is code that generates the above function:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
Wrapper *w = NewWrapper();
|
||||
Printf(w->def,"void foo(int n) {");
|
||||
Wrapper_add_local(w,"n",""); /* parameter n */
|
||||
Wrapper_add_local(w,"i", "int i;"); /* local i */
|
||||
Printv(w->code,"for (i = 0; i < n; i++) {",
|
||||
"printf(\"%d\n",i);",
|
||||
"}\n", NIL);
|
||||
Printf(w->code,"}\n");
|
||||
|
||||
/* Emit wrapper code */
|
||||
Wrapper_print(w,outf);
|
||||
DelWrapper(w);
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
Within different language modules, this process is obviously much more
|
||||
involved. However, this example shows the basic idea of how C/C++
|
||||
code is prepared for output.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,782 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and Android</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF">
|
||||
<H1><a name="Android">21 SWIG and Android</a></H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#Android_overview">Overview</a>
|
||||
<li><a href="#Android_examples">Android examples</a>
|
||||
<ul>
|
||||
<li><a href="#Android_examples_intro">Examples introduction</a>
|
||||
<li><a href="#Android_example_simple">Simple C example</a>
|
||||
<li><a href="#Android_example_class">C++ class example</a>
|
||||
<li><a href="#Android_examples_other">Other examples</a>
|
||||
</ul>
|
||||
<li><a href="#Android_stl">C++ STL</a>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
This chapter describes SWIG's support of Android.
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
<H2><a name="Android_overview">21.1 Overview</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
The Android chapter is fairly short as support for Android is the same as for Java, where the Java Native Interface (JNI) is
|
||||
used to call from Android Java into C or C++ compiled code.
|
||||
Everything in the <a href="Java.html#Java">Java chapter</a> applies to generating code for access from Android Java code.
|
||||
This chapter contains a few Android specific notes and examples.
|
||||
</p>
|
||||
|
||||
<H2><a name="Android_examples">21.2 Android examples</a></H2>
|
||||
|
||||
|
||||
<H3><a name="Android_examples_intro">21.2.1 Examples introduction</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
The examples require the <a href="https://developer.android.com/sdk/">Android SDK</a> and <a href="https://developer.android.com/ndk/">Android NDK</a> which can be installed as per instructions in the links.
|
||||
The Eclipse version is not required for these examples as just the command line tools are used (shown for Linux as the host, but Windows will be very similar, if not identical in most places).
|
||||
Add the SDK tools and NDK tools to your path and create a directory somewhere for your Android projects (adjust PATH as necessary to where you installed the tools):
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ export PATH=$HOME/android/android-sdk-linux_x86/tools:$HOME/android/android-sdk-linux_x86/platform-tools:$HOME/android/android-ndk-r6b:$PATH
|
||||
$ mkdir AndroidApps
|
||||
$ cd AndroidApps
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The examples use a target id of 1. This might need changing depending on your setup.
|
||||
After installation of the Android SDK, the available target ids can be viewed by running the command below.
|
||||
Please adjust the id to suit your target device.
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ android list targets
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The following examples are shipped with SWIG under the Examples/android directory and include a Makefile to build and install each example.
|
||||
</p>
|
||||
|
||||
<H3><a name="Android_example_simple">21.2.2 Simple C example</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
This simple C example shows how to call a C function as well as read and modify a global variable.
|
||||
First we'll create and build a pure Java Android app. Afterwards the JNI code will be generated by SWIG and built into the app.
|
||||
First create and build an app called <tt>SwigSimple</tt> in a subdirectory called <tt>simple</tt> using the commands below.
|
||||
Adjust the <tt>--target</tt> id as mentioned earlier in the <a href="Android.html#Android_examples_intro">Examples introduction</a>.
|
||||
<a href="http://developer.android.com/guide/developing/projects/projects-cmdline.html">Managing Projects from the Command Line</a> on the Android developer's site is a useful reference for these steps.
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ android create project --target 1 --name SwigSimple --path ./simple --activity SwigSimple --package org.swig.simple
|
||||
$ cd simple
|
||||
$ ant debug
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Modify <tt>src/org/swig/simple/SwigSimple.java</tt> from the default to:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
package org.swig.simple;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.ScrollView;
|
||||
import android.text.method.ScrollingMovementMethod;
|
||||
|
||||
public class SwigSimple extends Activity
|
||||
{
|
||||
TextView outputText = null;
|
||||
ScrollView scroller = null;
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.main);
|
||||
|
||||
outputText = (TextView)findViewById(R.id.OutputText);
|
||||
outputText.setText("Press 'Run' to start...\n");
|
||||
outputText.setMovementMethod(new ScrollingMovementMethod());
|
||||
|
||||
scroller = (ScrollView)findViewById(R.id.Scroller);
|
||||
}
|
||||
|
||||
public void onRunButtonClick(View view)
|
||||
{
|
||||
outputText.append("Started...\n");
|
||||
nativeCall();
|
||||
outputText.append("Finished!\n");
|
||||
|
||||
// Ensure scroll to end of text
|
||||
scroller.post(new Runnable() {
|
||||
public void run() {
|
||||
scroller.fullScroll(ScrollView.FOCUS_DOWN);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Calls into C/C++ code */
|
||||
public void nativeCall()
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The above simply adds a <i>Run</i> button and scrollable text view as the GUI aspects of the program.
|
||||
The associated resources need to be created, modify <tt>res/layout/main.xml</tt> as follows:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<Button
|
||||
android:id="@+id/RunButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Run..."
|
||||
android:onClick="onRunButtonClick"
|
||||
/>
|
||||
<ScrollView
|
||||
android:id="@+id/Scroller"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/OutputText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Rebuild the project with your changes:
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ ant debug
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Although there are no native function calls in the code, yet, you may want to check that this simple pure
|
||||
Java app runs before adding in the native calls.
|
||||
First, set up your Android device for hardware debugging, see <a href="http://developer.android.com/guide/developing/device.html">Using hardware devices</a> on the Android developer's site.
|
||||
When complete your device should be listed in those attached, something like:
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ adb devices
|
||||
List of devices attached
|
||||
A32-6DBE0001-9FF80000-015D62C3-02018028 device
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
This means you are now ready to install the application...
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ adb install bin/SwigSimple-debug.apk
|
||||
95 KB/s (4834 bytes in 0.049s)
|
||||
pkg: /data/local/tmp/SwigSimple-debug.apk
|
||||
Success
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The newly installed 'SwigSimple' app will be amongst all your other applications on the home screen. Run the app and it will show a <i>Run</i> button text box below it.
|
||||
Press the <i>Run</i> button to see the simple text output.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The application can be uninstalled like any other application and in fact must be uninstalled before installing an updated version. Uninstalling is quite easy too from your host computer:
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ adb uninstall org.swig.simple
|
||||
Success
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Now that you have a pure Java Android app working, let's add some JNI code generated from SWIG.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First create a <tt>jni</tt> subdirectory and then create some C source code in <tt>jni/example.c</tt>:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
/* File : example.c */
|
||||
|
||||
/* A global variable */
|
||||
double Foo = 3.0;
|
||||
|
||||
/* Compute the greatest common divisor of positive integers */
|
||||
int gcd(int x, int y) {
|
||||
int g;
|
||||
g = y;
|
||||
while (x > 0) {
|
||||
g = x;
|
||||
x = y % x;
|
||||
y = g;
|
||||
}
|
||||
return g;
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Create a SWIG interface file for this C code, <tt>jni/example.i</tt>:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
/* File : example.i */
|
||||
%module example
|
||||
|
||||
%inline %{
|
||||
extern int gcd(int x, int y);
|
||||
extern double Foo;
|
||||
%}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Invoke SWIG as follows:
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ swig -java -package org.swig.simple -outdir src/org/swig/simple -o jni/example_wrap.c jni/example.i
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
SWIG generates the following files:
|
||||
</p>
|
||||
<ul>
|
||||
<li><tt>src/org/swig/simple/exampleJNI.java</tt></li>
|
||||
<li><tt>src/org/swig/simple/example.java</tt></li>
|
||||
<li><tt>jni/example_wrap.c</tt></li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Next we need to create a standard Android NDK build system file <tt>jni/Android.mk</tt>:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
# File: Android.mk
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := example
|
||||
LOCAL_SRC_FILES := example_wrap.c example.c
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
See the <a href="https://developer.android.com/ndk/">Android NDK documentation</a> for more on the NDK build system and getting started with the NDK.
|
||||
A simple invocation of ndk-build will compile the .c files and generate a shared object/system library. Output will be similar to:
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ ndk-build
|
||||
Compile thumb : example <= example_wrap.c
|
||||
Compile thumb : example <= example.c
|
||||
SharedLibrary : libexample.so
|
||||
Install : libexample.so => libs/armeabi/libexample.so
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Now that the C JNI layer has been built, we can write Java code to call into the this layer.
|
||||
Modify the <tt>nativeCall</tt> method in <tt>src/org/swig/simple/SwigSimple.java</tt> to call the JNI code as follows and add the static constructor to load the system library containing the compiled JNI C code:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
/** Calls into C/C++ code */
|
||||
public void nativeCall()
|
||||
{
|
||||
// Call our gcd() function
|
||||
|
||||
int x = 42;
|
||||
int y = 105;
|
||||
int g = example.gcd(x, y);
|
||||
outputText.append("The greatest common divisor of " + x + " and " + y + " is " + g + "\n");
|
||||
|
||||
// Manipulate the Foo global variable
|
||||
|
||||
// Output its current value
|
||||
double foo = example.getFoo();
|
||||
outputText.append("Foo = " + foo + "\n");
|
||||
|
||||
// Change its value
|
||||
example.setFoo(3.1415926);
|
||||
|
||||
// See if the change took effect
|
||||
outputText.append("Foo = " + example.getFoo() + "\n");
|
||||
|
||||
// Restore value
|
||||
example.setFoo(foo);
|
||||
}
|
||||
|
||||
/** static constructor */
|
||||
static {
|
||||
System.loadLibrary("example");
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Compile the Java code as usual, uninstall the old version of the app if still installed and re-install the new app:
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ ant debug
|
||||
$ adb uninstall org.swig.simple
|
||||
$ adb install bin/SwigSimple-debug.apk
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Run the app again and this time you will see the output pictured below, showing the result of calls into the C code:
|
||||
</p>
|
||||
|
||||
<center><img src="android-simple.png" alt="Android screenshot of SwigSimple example"></center>
|
||||
|
||||
|
||||
<H3><a name="Android_example_class">21.2.3 C++ class example</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
The steps for calling C++ code are almost identical to those in the previous C code example.
|
||||
All the steps required to compile and use a simple hierarchy of classes for shapes are shown in this example.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First create an Android project called <tt>SwigClass</tt> in a subdirectory called <tt>class</tt>.
|
||||
The steps below create and build the JNI C++ app.
|
||||
Adjust the <tt>--target</tt> id as mentioned earlier in the <a href="Android.html#Android_examples_intro">Examples introduction</a>.
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ android create project --target 1 --name SwigClass --path ./class --activity SwigClass --package org.swig.classexample
|
||||
$ cd class
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Now create a <tt>jni</tt> subdirectory and then create a C++ header file <tt>jni/example.h</tt> which defines our
|
||||
hierarchy of shape classes:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
/* File : example.h */
|
||||
|
||||
class Shape {
|
||||
public:
|
||||
Shape() {
|
||||
nshapes++;
|
||||
}
|
||||
virtual ~Shape() {
|
||||
nshapes--;
|
||||
}
|
||||
double x, y;
|
||||
void move(double dx, double dy);
|
||||
virtual double area() = 0;
|
||||
virtual double perimeter() = 0;
|
||||
static int nshapes;
|
||||
};
|
||||
|
||||
class Circle : public Shape {
|
||||
private:
|
||||
double radius;
|
||||
public:
|
||||
Circle(double r) : radius(r) { }
|
||||
virtual double area();
|
||||
virtual double perimeter();
|
||||
};
|
||||
|
||||
class Square : public Shape {
|
||||
private:
|
||||
double width;
|
||||
public:
|
||||
Square(double w) : width(w) { }
|
||||
virtual double area();
|
||||
virtual double perimeter();
|
||||
};
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
and create the implementation in the <tt>jni/example.cpp</tt> file:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
/* File : example.cpp */
|
||||
|
||||
#include "example.h"
|
||||
#define M_PI 3.14159265358979323846
|
||||
|
||||
/* Move the shape to a new location */
|
||||
void Shape::move(double dx, double dy) {
|
||||
x += dx;
|
||||
y += dy;
|
||||
}
|
||||
|
||||
int Shape::nshapes = 0;
|
||||
|
||||
double Circle::area() {
|
||||
return M_PI*radius*radius;
|
||||
}
|
||||
|
||||
double Circle::perimeter() {
|
||||
return 2*M_PI*radius;
|
||||
}
|
||||
|
||||
double Square::area() {
|
||||
return width*width;
|
||||
}
|
||||
|
||||
double Square::perimeter() {
|
||||
return 4*width;
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Create a SWIG interface file for this C++ code in <tt>jni/example.i</tt>:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
/* File : example.i */
|
||||
%module example
|
||||
|
||||
%{
|
||||
#include "example.h"
|
||||
%}
|
||||
|
||||
/* Let's just grab the original header file here */
|
||||
%include "example.h"
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Invoke SWIG as follows, note that the -c++ option is required for C++ code:
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ swig -c++ -java -package org.swig.classexample -outdir src/org/swig/classexample -o jni/example_wrap.cpp jni/example.i
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
SWIG generates the following files:
|
||||
</p>
|
||||
<ul>
|
||||
<li><tt>src/org/swig/classexample/Square.java</tt></li>
|
||||
<li><tt>src/org/swig/classexample/exampleJNI.java</tt></li>
|
||||
<li><tt>src/org/swig/classexample/example.java</tt></li>
|
||||
<li><tt>src/org/swig/classexample/Circle.java</tt></li>
|
||||
<li><tt>src/org/swig/classexample/Shape.java</tt></li>
|
||||
<li><tt>jni/example_wrap.cpp</tt></li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Next we need to create an Android NDK build system file for compiling the C++ code <tt>jni/Android.mk</tt>.
|
||||
The <tt>-frtti</tt> compiler flag isn't strictly needed for this example, but is needed for any code that uses C++ RTTI:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
# File: Android.mk
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := example
|
||||
LOCAL_SRC_FILES := example_wrap.cpp example.cpp
|
||||
LOCAL_CFLAGS := -frtti
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
|
||||
<p>
|
||||
A simple invocation of ndk-build will compile the .cpp files and generate a shared object/system library. Output will be similar to:
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ ndk-build
|
||||
Compile++ thumb : example <= example_wrap.cpp
|
||||
Compile++ thumb : example <= example.cpp
|
||||
StaticLibrary : libstdc++.a
|
||||
SharedLibrary : libexample.so
|
||||
Install : libexample.so => libs/armeabi/libexample.so
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Now that the C JNI layer has been built, we can write Java code to call into this layer.
|
||||
Modify <tt>src/org/swig/classexample/SwigClass.java</tt> from the default to:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
package org.swig.classexample;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.ScrollView;
|
||||
import android.text.method.ScrollingMovementMethod;
|
||||
|
||||
public class SwigClass extends Activity
|
||||
{
|
||||
TextView outputText = null;
|
||||
ScrollView scroller = null;
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.main);
|
||||
|
||||
outputText = (TextView)findViewById(R.id.OutputText);
|
||||
outputText.setText("Press 'Run' to start...\n");
|
||||
outputText.setMovementMethod(new ScrollingMovementMethod());
|
||||
|
||||
scroller = (ScrollView)findViewById(R.id.Scroller);
|
||||
}
|
||||
|
||||
public void onRunButtonClick(View view)
|
||||
{
|
||||
outputText.append("Started...\n");
|
||||
nativeCall();
|
||||
outputText.append("Finished!\n");
|
||||
|
||||
// Ensure scroll to end of text
|
||||
scroller.post(new Runnable() {
|
||||
public void run() {
|
||||
scroller.fullScroll(ScrollView.FOCUS_DOWN);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Calls into C/C++ code */
|
||||
public void nativeCall()
|
||||
{
|
||||
// ----- Object creation -----
|
||||
|
||||
outputText.append( "Creating some objects:\n" );
|
||||
Circle c = new Circle(10);
|
||||
outputText.append( " Created circle " + c + "\n");
|
||||
Square s = new Square(10);
|
||||
outputText.append( " Created square " + s + "\n");
|
||||
|
||||
// ----- Access a static member -----
|
||||
|
||||
outputText.append( "\nA total of " + Shape.getNshapes() + " shapes were created\n" );
|
||||
|
||||
// ----- Member data access -----
|
||||
|
||||
// Notice how we can do this using functions specific to
|
||||
// the 'Circle' class.
|
||||
c.setX(20);
|
||||
c.setY(30);
|
||||
|
||||
// Now use the same functions in the base class
|
||||
Shape shape = s;
|
||||
shape.setX(-10);
|
||||
shape.setY(5);
|
||||
|
||||
outputText.append( "\nHere is their current position:\n" );
|
||||
outputText.append( " Circle = (" + c.getX() + " " + c.getY() + ")\n" );
|
||||
outputText.append( " Square = (" + s.getX() + " " + s.getY() + ")\n" );
|
||||
|
||||
// ----- Call some methods -----
|
||||
|
||||
outputText.append( "\nHere are some properties of the shapes:\n" );
|
||||
Shape[] shapes = {c, s};
|
||||
for (int i=0; i<shapes.length; i++)
|
||||
{
|
||||
outputText.append( " " + shapes[i].toString() + "\n" );
|
||||
outputText.append( " area = " + shapes[i].area() + "\n" );
|
||||
outputText.append( " perimeter = " + shapes[i].perimeter() + "\n" );
|
||||
}
|
||||
|
||||
// Notice how the area() and perimeter() functions really
|
||||
// invoke the appropriate virtual method on each object.
|
||||
|
||||
// ----- Delete everything -----
|
||||
|
||||
outputText.append( "\nGuess I'll clean up now\n" );
|
||||
|
||||
// Note: this invokes the virtual destructor
|
||||
// You could leave this to the garbage collector
|
||||
c.delete();
|
||||
s.delete();
|
||||
|
||||
outputText.append( Shape.getNshapes() + " shapes remain\n" );
|
||||
outputText.append( "Goodbye\n" );
|
||||
}
|
||||
|
||||
/** static constructor */
|
||||
static {
|
||||
System.loadLibrary("example");
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Note the static constructor and the interesting JNI code is in the <tt>nativeCall</tt> method.
|
||||
The remaining code deals with the GUI aspects which are identical to the previous C simple example. Modify <tt>res/layout/main.xml</tt> to contain the xml for the 'Run' button and scrollable text view:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<Button
|
||||
android:id="@+id/RunButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Run..."
|
||||
android:onClick="onRunButtonClick"
|
||||
/>
|
||||
<ScrollView
|
||||
android:id="@+id/Scroller"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/OutputText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
|
||||
<p>
|
||||
Compile the Java code as usual, uninstall the old version of the app if installed and re-install the new app:
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ ant debug
|
||||
$ adb uninstall org.swig.classexample
|
||||
$ adb install bin/SwigClass-debug.apk
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Run the app to see the result of calling the C++ code from Java:
|
||||
</p>
|
||||
|
||||
<center><img src="android-class.png" alt="Android screenshot of SwigClass example"></center>
|
||||
|
||||
<H3><a name="Android_examples_other">21.2.4 Other examples</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
The Examples/android directory contains further examples which can be run and installed in a similar manner to the previous two examples.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that the 'extend' example is demonstrates the directors feature.
|
||||
Normally C++ exception handling and the STL is not available by default in the version of g++ shipped with Android, but this example turns these features on as described in the next section.
|
||||
</p>
|
||||
|
||||
<H2><a name="Android_stl">21.3 C++ STL</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
Should the C++ Standard Template Library (STL) be required, an <tt>Application.mk</tt> file needs to be created
|
||||
in the same directory as the <tt>Android.mk</tt> directory containing information about the STL to use.
|
||||
See the NDK documentation in the $NDKROOT/docs folder especially CPLUSPLUS-SUPPORT.html.
|
||||
Below is an example of the <tt>Application.mk</tt> file to make the STLport static library available for use:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
# File: Application.mk
|
||||
APP_STL := gnustl_static
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,497 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Argument Handling</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<H1><a name="Arguments">12 Argument Handling</a></H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#Arguments_nn2">The typemaps.i library</a>
|
||||
<ul>
|
||||
<li><a href="#Arguments_nn3">Introduction</a>
|
||||
<li><a href="#Arguments_nn4">Input parameters</a>
|
||||
<li><a href="#Arguments_nn5">Output parameters</a>
|
||||
<li><a href="#Arguments_nn6">Input/Output parameters</a>
|
||||
<li><a href="#Arguments_nn7">Using different names</a>
|
||||
</ul>
|
||||
<li><a href="#Arguments_nn8">Applying constraints to input values</a>
|
||||
<ul>
|
||||
<li><a href="#Arguments_nn9">Simple constraint example</a>
|
||||
<li><a href="#Arguments_nn10">Constraint methods</a>
|
||||
<li><a href="#Arguments_nn11">Applying constraints to new datatypes</a>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
In Chapter 5, SWIG's treatment of basic datatypes and pointers was
|
||||
described. In particular, primitive types such as <tt>int</tt> and
|
||||
<tt>double</tt> are mapped to corresponding types in the target
|
||||
language. For everything else, pointers are used to refer to
|
||||
structures, classes, arrays, and other user-defined datatypes.
|
||||
However, in certain applications it is desirable to change SWIG's
|
||||
handling of a specific datatype. For example, you might want to
|
||||
return multiple values through the arguments of a function. This chapter
|
||||
describes some of the techniques for doing this.
|
||||
</p>
|
||||
|
||||
<H2><a name="Arguments_nn2">12.1 The typemaps.i library</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
This section describes the <tt>typemaps.i</tt> library file--commonly used to
|
||||
change certain properties of argument conversion.
|
||||
</p>
|
||||
|
||||
<H3><a name="Arguments_nn3">12.1.1 Introduction</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Suppose you had a C function like this:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
void add(double a, double b, double *result) {
|
||||
*result = a + b;
|
||||
}
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
From reading the source code, it is clear that the function is storing
|
||||
a value in the <tt>double *result</tt> parameter. However, since SWIG
|
||||
does not examine function bodies, it has no way to know that this is
|
||||
the underlying behavior.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
One way to deal with this is to use the
|
||||
<tt>typemaps.i</tt> library file and write interface code like this:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
// Simple example using typemaps
|
||||
%module example
|
||||
%include "typemaps.i"
|
||||
|
||||
%apply double *OUTPUT { double *result };
|
||||
%inline %{
|
||||
extern void add(double a, double b, double *result);
|
||||
%}
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
The <tt>%apply</tt> directive tells SWIG that you are going to apply
|
||||
a special type handling rule to a type. The "<tt>double *OUTPUT</tt>" specification is the
|
||||
name of a rule that defines how to return an output value from an argument of type
|
||||
<tt>double *</tt>. This rule gets applied to all of the datatypes
|
||||
listed in curly braces-- in this case "<tt>double *result</tt>".</p>
|
||||
|
||||
<p>
|
||||
When the resulting module is created, you can now use the function
|
||||
like this (shown for Python):
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
>>> a = add(3, 4)
|
||||
>>> print a
|
||||
7
|
||||
>>>
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
In this case, you can see how the output value normally returned in
|
||||
the third argument has magically been transformed into a function
|
||||
return value. Clearly this makes the function much easier to use
|
||||
since it is no longer necessary to manufacture a special <tt>double
|
||||
*</tt> object and pass it to the function somehow.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Once a typemap has been applied to a type, it stays in effect for all future occurrences
|
||||
of the type and name. For example, you could write the following:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%module example
|
||||
%include "typemaps.i"
|
||||
|
||||
%apply double *OUTPUT { double *result };
|
||||
|
||||
%inline %{
|
||||
extern void add(double a, double b, double *result);
|
||||
extern void sub(double a, double b, double *result);
|
||||
extern void mul(double a, double b, double *result);
|
||||
extern void div(double a, double b, double *result);
|
||||
%}
|
||||
...
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
In this case, the <tt>double *OUTPUT</tt> rule is applied to all of the functions that follow.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Typemap transformations can even be extended to multiple return values.
|
||||
For example, consider this code:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%include "typemaps.i"
|
||||
%apply int *OUTPUT { int *width, int *height };
|
||||
|
||||
// Returns a pair (width, height)
|
||||
void getwinsize(int winid, int *width, int *height);
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
In this case, the function returns multiple values, allowing it to be used like this:
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
>>> w, h = genwinsize(wid)
|
||||
>>> print w
|
||||
400
|
||||
>>> print h
|
||||
300
|
||||
>>>
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
It should also be noted that although the <tt>%apply</tt> directive is
|
||||
used to associate typemap rules to datatypes, you can also use the
|
||||
rule names directly in arguments. For example, you could write this:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
// Simple example using typemaps
|
||||
%module example
|
||||
%include "typemaps.i"
|
||||
|
||||
%{
|
||||
extern void add(double a, double b, double *OUTPUT);
|
||||
%}
|
||||
extern void add(double a, double b, double *OUTPUT);
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Typemaps stay in effect until they are explicitly deleted or redefined to something
|
||||
else. To clear a typemap, the <tt>%clear</tt> directive should be used. For example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%clear double *result; // Remove all typemaps for double *result
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<H3><a name="Arguments_nn4">12.1.2 Input parameters</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
The following typemaps instruct SWIG that a pointer really only holds a single
|
||||
input value:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
int *INPUT
|
||||
short *INPUT
|
||||
long *INPUT
|
||||
unsigned int *INPUT
|
||||
unsigned short *INPUT
|
||||
unsigned long *INPUT
|
||||
double *INPUT
|
||||
float *INPUT
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
When used, it allows values to be passed instead of pointers. For example, consider this
|
||||
function:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
double add(double *a, double *b) {
|
||||
return *a+*b;
|
||||
}
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Now, consider this SWIG interface:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%module example
|
||||
%include "typemaps.i"
|
||||
...
|
||||
%{
|
||||
extern double add(double *, double *);
|
||||
%}
|
||||
extern double add(double *INPUT, double *INPUT);
|
||||
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
When the function is used in the scripting language interpreter, it will work like this:
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
result = add(3, 4)
|
||||
</pre></div>
|
||||
|
||||
<H3><a name="Arguments_nn5">12.1.3 Output parameters</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
The following typemap rules tell SWIG that pointer is the output value of a
|
||||
function. When used, you do not need to supply the argument when
|
||||
calling the function. Instead, one or more output values are returned.
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
int *OUTPUT
|
||||
short *OUTPUT
|
||||
long *OUTPUT
|
||||
unsigned int *OUTPUT
|
||||
unsigned short *OUTPUT
|
||||
unsigned long *OUTPUT
|
||||
double *OUTPUT
|
||||
float *OUTPUT
|
||||
|
||||
</pre></div>
|
||||
<p>
|
||||
These methods can be used as shown in an earlier example. For example, if you have this C function :</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
void add(double a, double b, double *c) {
|
||||
*c = a+b;
|
||||
}
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
A SWIG interface file might look like this :</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%module example
|
||||
%include "typemaps.i"
|
||||
...
|
||||
%inline %{
|
||||
extern void add(double a, double b, double *OUTPUT);
|
||||
%}
|
||||
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
In this case, only a single output value is returned, but this is not
|
||||
a restriction. An arbitrary number of output values can be returned by applying
|
||||
the output rules to more than one argument (as shown previously).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If the function also returns a value, it is returned along with the argument. For example,
|
||||
if you had this:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
extern int foo(double a, double b, double *OUTPUT);
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
The function will return two values like this:
|
||||
</p>
|
||||
|
||||
<div class="targetlang">
|
||||
<pre>
|
||||
iresult, dresult = foo(3.5, 2)
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<H3><a name="Arguments_nn6">12.1.4 Input/Output parameters</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
When a pointer serves as both an input and output value you can use
|
||||
the following typemaps :</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
int *INOUT
|
||||
short *INOUT
|
||||
long *INOUT
|
||||
unsigned int *INOUT
|
||||
unsigned short *INOUT
|
||||
unsigned long *INOUT
|
||||
double *INOUT
|
||||
float *INOUT
|
||||
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
A C function that uses this might be something like this:</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
void negate(double *x) {
|
||||
*x = -(*x);
|
||||
}
|
||||
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
To make x function as both and input and output value, declare the
|
||||
function like this in an interface file :</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%module example
|
||||
%include "typemaps.i"
|
||||
...
|
||||
%{
|
||||
extern void negate(double *);
|
||||
%}
|
||||
extern void negate(double *INOUT);
|
||||
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Now within a script, you can simply call the function normally :</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
a = negate(3); # a = -3 after calling this
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
One subtle point of the <tt>INOUT</tt> rule is that many scripting languages
|
||||
enforce mutability constraints on primitive objects (meaning that simple objects
|
||||
like integers and strings aren't supposed to change). Because of this, you can't
|
||||
just modify the object's value in place as the underlying C function does in this example.
|
||||
Therefore, the <tt>INOUT</tt> rule returns the modified value as a new object
|
||||
rather than directly overwriting the value of the original input object.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Compatibility note :</b> The <tt>INOUT</tt> rule used to be known as <tt>BOTH</tt> in earlier versions of
|
||||
SWIG. Backwards compatibility is preserved, but deprecated.
|
||||
</p>
|
||||
|
||||
<H3><a name="Arguments_nn7">12.1.5 Using different names</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
As previously shown, the <tt>%apply</tt> directive can be used to apply the <tt>INPUT</tt>, <tt>OUTPUT</tt>, and
|
||||
<tt>INOUT</tt> typemaps to different argument names. For example:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
// Make double *result an output value
|
||||
%apply double *OUTPUT { double *result };
|
||||
|
||||
// Make Int32 *in an input value
|
||||
%apply int *INPUT { Int32 *in };
|
||||
|
||||
// Make long *x inout
|
||||
%apply long *INOUT {long *x};
|
||||
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
To clear a rule, the <tt>%clear</tt> directive is used:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%clear double *result;
|
||||
%clear Int32 *in, long *x;
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Typemap declarations are lexically scoped so a typemap takes effect from the point of definition to the end of the
|
||||
file or a matching <tt>%clear</tt> declaration.
|
||||
</p>
|
||||
|
||||
<H2><a name="Arguments_nn8">12.2 Applying constraints to input values</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
In addition to changing the handling of various input values, it is
|
||||
also possible to use typemaps to apply constraints. For example, maybe you want to
|
||||
insure that a value is positive, or that a pointer is non-NULL. This
|
||||
can be accomplished including the <tt>constraints.i</tt> library file.
|
||||
</p>
|
||||
|
||||
<H3><a name="Arguments_nn9">12.2.1 Simple constraint example</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
The constraints library is best illustrated by the following interface
|
||||
file :</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
// Interface file with constraints
|
||||
%module example
|
||||
%include "constraints.i"
|
||||
|
||||
double exp(double x);
|
||||
double log(double POSITIVE); // Allow only positive values
|
||||
double sqrt(double NONNEGATIVE); // Non-negative values only
|
||||
double inv(double NONZERO); // Non-zero values
|
||||
void free(void *NONNULL); // Non-NULL pointers only
|
||||
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
The behavior of this file is exactly as you would expect. If any of
|
||||
the arguments violate the constraint condition, a scripting language
|
||||
exception will be raised. As a result, it is possible to catch bad
|
||||
values, prevent mysterious program crashes and so on.</p>
|
||||
|
||||
<H3><a name="Arguments_nn10">12.2.2 Constraint methods</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
The following constraints are currently available</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
POSITIVE Any number > 0 (not zero)
|
||||
NEGATIVE Any number < 0 (not zero)
|
||||
NONNEGATIVE Any number >= 0
|
||||
NONPOSITIVE Any number <= 0
|
||||
NONZERO Nonzero number
|
||||
NONNULL Non-NULL pointer (pointers only).
|
||||
|
||||
</pre></div>
|
||||
|
||||
<H3><a name="Arguments_nn11">12.2.3 Applying constraints to new datatypes</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
The constraints library only supports the primitive C datatypes, but it
|
||||
is easy to apply it to new datatypes using <tt>%apply</tt>. For
|
||||
example :</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
// Apply a constraint to a Real variable
|
||||
%apply Number POSITIVE { Real in };
|
||||
|
||||
// Apply a constraint to a pointer type
|
||||
%apply Pointer NONNULL { Vector * };
|
||||
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
The special types of "Number" and "Pointer" can be applied to any
|
||||
numeric and pointer variable type respectively. To later remove a
|
||||
constraint, the <tt>%clear</tt> directive can be used :</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%clear Real in;
|
||||
%clear Vector *;
|
||||
</pre></div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,474 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>ccache-swig(1) manpage</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<H1><a name="CCache">20 Using SWIG with ccache - ccache-swig(1) manpage</a></H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#CCache_nn2">NAME</a>
|
||||
<li><a href="#CCache_nn3">SYNOPSIS</a>
|
||||
<li><a href="#CCache_nn4">DESCRIPTION</a>
|
||||
<li><a href="#CCache_nn5">OPTIONS SUMMARY</a>
|
||||
<li><a href="#CCache_nn6">OPTIONS</a>
|
||||
<li><a href="#CCache_nn7">INSTALLATION</a>
|
||||
<li><a href="#CCache_nn8">EXTRA OPTIONS</a>
|
||||
<li><a href="#CCache_nn9">ENVIRONMENT VARIABLES</a>
|
||||
<li><a href="#CCache_nn10">CACHE SIZE MANAGEMENT</a>
|
||||
<li><a href="#CCache_nn11">CACHE COMPRESSION</a>
|
||||
<li><a href="#CCache_nn12">HOW IT WORKS</a>
|
||||
<li><a href="#CCache_nn13">USING CCACHE WITH DISTCC</a>
|
||||
<li><a href="#CCache_nn14">SHARING A CACHE</a>
|
||||
<li><a href="#CCache_nn15">HISTORY</a>
|
||||
<li><a href="#CCache_nn16">DIFFERENCES FROM COMPILERCACHE</a>
|
||||
<li><a href="#CCache_nn17">CREDITS</a>
|
||||
<li><a href="#CCache_nn18">AUTHOR</a>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
<H2><a name="CCache_nn2">20.1 NAME</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
|
||||
ccache-swig - a fast compiler cache
|
||||
|
||||
<p>
|
||||
<H2><a name="CCache_nn3">20.2 SYNOPSIS</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
ccache-swig [OPTION]
|
||||
<p>
|
||||
ccache-swig <compiler> [COMPILER OPTIONS]
|
||||
<p>
|
||||
<compiler> [COMPILER OPTIONS]
|
||||
<p>
|
||||
<H2><a name="CCache_nn4">20.3 DESCRIPTION</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
ccache-swig is a compiler cache. It speeds up re-compilation of C/C++/SWIG code
|
||||
by caching previous compiles and detecting when the same compile is
|
||||
being done again. ccache-swig is ccache plus support for SWIG. ccache
|
||||
and ccache-swig are used interchangeably in this document.
|
||||
<p>
|
||||
<H2><a name="CCache_nn5">20.4 OPTIONS SUMMARY</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
Here is a summary of the options to ccache-swig.
|
||||
<p>
|
||||
<pre>
|
||||
|
||||
-s show statistics summary
|
||||
-z zero statistics
|
||||
-c run a cache cleanup
|
||||
-C clear the cache completely
|
||||
-F <n> set maximum files in cache
|
||||
-M <n> set maximum size of cache (use G, M or K)
|
||||
-h this help page
|
||||
-V print version number
|
||||
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<H2><a name="CCache_nn6">20.5 OPTIONS</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
These options only apply when you invoke ccache as "ccache-swig". When
|
||||
invoked as a compiler none of these options apply. In that case your
|
||||
normal compiler options apply and you should refer to your compilers
|
||||
documentation.
|
||||
<p>
|
||||
<dl>
|
||||
<p><dt><strong><strong>-h</strong></strong><dd> Print a options summary page
|
||||
<p>
|
||||
<p><dt><strong><strong>-s</strong></strong><dd> Print the current statistics summary for the cache. The
|
||||
statistics are stored spread across the subdirectories of the
|
||||
cache. Using "ccache-swig -s" adds up the statistics across all
|
||||
subdirectories and prints the totals.
|
||||
<p>
|
||||
<p><dt><strong><strong>-z</strong></strong><dd> Zero the cache statistics.
|
||||
<p>
|
||||
<p><dt><strong><strong>-V</strong></strong><dd> Print the ccache version number
|
||||
<p>
|
||||
<p><dt><strong><strong>-c</strong></strong><dd> Clean the cache and re-calculate the cache file count and
|
||||
size totals. Normally the -c option should not be necessary as ccache
|
||||
keeps the cache below the specified limits at runtime and keeps
|
||||
statistics up to date on each compile. This option is mostly useful
|
||||
if you manually modify the cache contents or believe that the cache
|
||||
size statistics may be inaccurate.
|
||||
<p>
|
||||
<p><dt><strong><strong>-C</strong></strong><dd> Clear the entire cache, removing all cached files.
|
||||
<p>
|
||||
<p><dt><strong><strong>-F <maxfiles></strong></strong><dd> This sets the maximum number of files allowed in
|
||||
the cache. The value is stored inside the cache directory and applies
|
||||
to all future compiles. Due to the way the value is stored the actual
|
||||
value used is always rounded down to the nearest multiple of 16.
|
||||
<p>
|
||||
<p><dt><strong><strong>-M <maxsize></strong></strong><dd> This sets the maximum cache size. You can specify
|
||||
a value in gigabytes, megabytes or kilobytes by appending a G, M or K
|
||||
to the value. The default is gigabytes. The actual value stored is
|
||||
rounded down to the nearest multiple of 16 kilobytes.
|
||||
<p>
|
||||
</dl>
|
||||
<p>
|
||||
<H2><a name="CCache_nn7">20.6 INSTALLATION</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
There are two ways to use ccache. You can either prefix your compile
|
||||
commands with "ccache-swig" or you can create a symbolic link between
|
||||
ccache-swig and the names of your compilers. The first method is most
|
||||
convenient if you just want to try out ccache or wish to use it for
|
||||
some specific projects. The second method is most useful for when you
|
||||
wish to use ccache for all your compiles.
|
||||
<p>
|
||||
To install for usage by the first method just copy ccache-swig to somewhere
|
||||
in your path.
|
||||
<p>
|
||||
To install for the second method do something like this:
|
||||
<pre>
|
||||
|
||||
cp ccache-swig /usr/local/bin/
|
||||
ln -s /usr/local/bin/ccache-swig /usr/local/bin/gcc
|
||||
ln -s /usr/local/bin/ccache-swig /usr/local/bin/g++
|
||||
ln -s /usr/local/bin/ccache-swig /usr/local/bin/cc
|
||||
ln -s /usr/local/bin/ccache-swig /usr/local/bin/swig
|
||||
|
||||
</pre>
|
||||
|
||||
This will work as long as /usr/local/bin comes before the path to gcc
|
||||
(which is usually in /usr/bin). After installing you may wish to run
|
||||
"which gcc" to make sure that the correct link is being used.
|
||||
<p>
|
||||
Note! Do not use a hard link, use a symbolic link. A hardlink will
|
||||
cause "interesting" problems.
|
||||
<p>
|
||||
<H2><a name="CCache_nn8">20.7 EXTRA OPTIONS</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
When run as a compiler front end ccache usually just takes the same
|
||||
command line options as the compiler you are using. The only exception
|
||||
to this is the option '--ccache-skip'. That option can be used to tell
|
||||
ccache that the next option is definitely not a input filename, and
|
||||
should be passed along to the compiler as-is.
|
||||
<p>
|
||||
The reason this can be important is that ccache does need to parse the
|
||||
command line and determine what is an input filename and what is a
|
||||
compiler option, as it needs the input filename to determine the name
|
||||
of the resulting object file (among other things). The heuristic
|
||||
ccache uses in this parse is that any string on the command line that
|
||||
exists as a file is treated as an input file name (usually a C
|
||||
file). By using --ccache-skip you can force an option to not be
|
||||
treated as an input file name and instead be passed along to the
|
||||
compiler as a command line option.
|
||||
<p>
|
||||
<H2><a name="CCache_nn9">20.8 ENVIRONMENT VARIABLES</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
ccache uses a number of environment variables to control operation. In
|
||||
most cases you won't need any of these as the defaults will be fine.
|
||||
<p>
|
||||
<dl>
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_DIR</strong></strong><dd> the CCACHE_DIR environment variable specifies
|
||||
where ccache will keep its cached compiler output. The default is
|
||||
"$HOME/.ccache".
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_TEMPDIR</strong></strong><dd> the CCACHE_TEMPDIR environment variable specifies
|
||||
where ccache will put temporary files. The default is the same as
|
||||
CCACHE_DIR. Note that the CCACHE_TEMPDIR path must be on the same
|
||||
filesystem as the CCACHE_DIR path, so that renames of files between
|
||||
the two directories can work.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_LOGFILE</strong></strong><dd> If you set the CCACHE_LOGFILE environment
|
||||
variable then ccache will write some log information on cache hits
|
||||
and misses in that file. This is useful for tracking down problems.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_VERBOSE</strong></strong><dd> If you set the CCACHE_VERBOSE environment
|
||||
variable then ccache will display on stdout all the compiler invocations
|
||||
that it makes. This can useful for debugging unexpected problems.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_PATH</strong></strong><dd> You can optionally set CCACHE_PATH to a colon
|
||||
separated path where ccache will look for the real compilers. If you
|
||||
don't do this then ccache will look for the first executable matching
|
||||
the compiler name in the normal PATH that isn't a symbolic link to
|
||||
ccache itself.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_CC</strong></strong><dd> You can optionally set CCACHE_CC to force the name
|
||||
of the compiler to use. If you don't do this then ccache works it out
|
||||
from the command line.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_PREFIX</strong></strong><dd> This option adds a prefix to the command line
|
||||
that ccache runs when invoking the compiler. Also see the section
|
||||
below on using ccache with distcc.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_DISABLE</strong></strong><dd> If you set the environment variable
|
||||
CCACHE_DISABLE then ccache will just call the real compiler,
|
||||
bypassing the cache completely.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_READONLY</strong></strong><dd> the CCACHE_READONLY environment variable
|
||||
tells ccache to attempt to use existing cached object files, but not
|
||||
to try to add anything new to the cache. If you are using this because
|
||||
your CCACHE_DIR is read-only, then you may find that you also need to
|
||||
set CCACHE_TEMPDIR as otherwise ccache will fail to create the
|
||||
temporary files.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_CPP2</strong></strong><dd> If you set the environment variable CCACHE_CPP2
|
||||
then ccache will not use the optimisation of avoiding the 2nd call to
|
||||
the pre-processor by compiling the pre-processed output that was used
|
||||
for finding the hash in the case of a cache miss. This is primarily a
|
||||
debugging option, although it is possible that some unusual compilers
|
||||
will have problems with the intermediate filename extensions used in
|
||||
this optimisation, in which case this option could allow ccache to be
|
||||
used.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_NOCOMPRESS</strong></strong><dd> If you set the environment variable
|
||||
CCACHE_NOCOMPRESS then there is no compression used on files that go
|
||||
into the cache. However, this setting has no effect on how files are
|
||||
retrieved from the cache, compressed results will still be usable.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_NOSTATS</strong></strong><dd> If you set the environment variable
|
||||
CCACHE_NOSTATS then ccache will not update the statistics files on
|
||||
each compile.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_NLEVELS</strong></strong><dd> The environment variable CCACHE_NLEVELS allows
|
||||
you to choose the number of levels of hash in the cache directory. The
|
||||
default is 2. The minimum is 1 and the maximum is 8.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_HARDLINK</strong></strong><dd> If you set the environment variable
|
||||
CCACHE_HARDLINK then ccache will attempt to use hard links from the
|
||||
cache directory when creating the compiler output rather than using a
|
||||
file copy. Using hard links is faster, but can confuse programs like
|
||||
'make' that rely on modification times. Hard links are never made for
|
||||
compressed cache files.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_RECACHE</strong></strong><dd> This forces ccache to not use any cached
|
||||
results, even if it finds them. New results are still cached, but
|
||||
existing cache entries are ignored.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_UMASK</strong></strong><dd> This sets the umask for ccache and all child
|
||||
processes (such as the compiler). This is mostly useful when you wish
|
||||
to share your cache with other users. Note that this also affects the
|
||||
file permissions set on the object files created from your
|
||||
compilations.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_HASHDIR</strong></strong><dd> This tells ccache to hash the current working
|
||||
directory when calculating the hash that is used to distinguish two
|
||||
compiles. This prevents a problem with the storage of the current
|
||||
working directory in the debug info of a object file, which can lead
|
||||
ccache to give a cached object file that has the working directory in
|
||||
the debug info set incorrectly. This option is off by default as the
|
||||
incorrect setting of this debug info rarely causes problems. If you
|
||||
strike problems with gdb not using the correct directory then enable
|
||||
this option.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_UNIFY</strong></strong><dd> If you set the environment variable CCACHE_UNIFY
|
||||
then ccache will use the C/C++ unifier when hashing the pre-processor
|
||||
output if -g is not used in the compile. The unifier is slower than a
|
||||
normal hash, so setting this environment variable loses a little bit
|
||||
of speed, but it means that ccache can take advantage of not
|
||||
recompiling when the changes to the source code consist of
|
||||
reformatting only. Note that using CCACHE_UNIFY changes the hash, so
|
||||
cached compiles with CCACHE_UNIFY set cannot be used when
|
||||
CCACHE_UNIFY is not set and vice versa. The reason the unifier is off
|
||||
by default is that it can give incorrect line number information in
|
||||
compiler warning messages.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_EXTENSION</strong></strong><dd> Normally ccache tries to automatically
|
||||
determine the extension to use for intermediate C pre-processor files
|
||||
based on the type of file being compiled. Unfortunately this sometimes
|
||||
doesn't work, for example when using the aCC compiler on HP-UX. On
|
||||
systems like this you can use the CCACHE_EXTENSION option to override
|
||||
the default. On HP-UX set this environment variable to "i" if you use
|
||||
the aCC compiler.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_STRIPC</strong></strong><dd> If you set the environment variable
|
||||
CCACHE_STRIPC then ccache will strip the -c option when invoking
|
||||
the preprocessor. This option is primarily for the Sun Workshop
|
||||
C++ compiler as without this option an unwarranted warning is displayed:
|
||||
CC: Warning: "-E" redefines product from "object" to "source (stdout)"
|
||||
when -E and -c is used together.
|
||||
<p>
|
||||
<p><dt><strong><strong>CCACHE_SWIG</strong></strong><dd> When using SWIG as the compiler and it does not
|
||||
have 'swig' in the executable name, then the CCACHE_SWIG environment
|
||||
variable needs to be set in order for ccache to work correctly with
|
||||
SWIG. The use of CCACHE_CPP2 is also recommended for SWIG due to some
|
||||
preprocessor quirks, however, use of CCACHE_CPP2 can often be skipped
|
||||
-- check your generated code with and without this option set. Known
|
||||
problems are using preprocessor directives within %inline blocks and
|
||||
the use of '#pragma SWIG'.
|
||||
<p>
|
||||
</dl>
|
||||
<p>
|
||||
<H2><a name="CCache_nn10">20.9 CACHE SIZE MANAGEMENT</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
By default ccache has a one gigabyte limit on the cache size and no
|
||||
maximum number of files. You can set a different limit using the
|
||||
"ccache -M" and "ccache -F" options, which set the size and number of
|
||||
files limits.
|
||||
<p>
|
||||
When these limits are reached ccache will reduce the cache to 20%
|
||||
below the numbers you specified in order to avoid doing the cache
|
||||
clean operation too often.
|
||||
<p>
|
||||
<H2><a name="CCache_nn11">20.10 CACHE COMPRESSION</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
By default on most platforms ccache will compress all files it puts
|
||||
into the cache
|
||||
using the zlib compression. While this involves a negligible
|
||||
performance slowdown, it significantly increases the number of files
|
||||
that fit in the cache. You can turn off compression setting the
|
||||
CCACHE_NOCOMPRESS environment variable.
|
||||
<p>
|
||||
<H2><a name="CCache_nn12">20.11 HOW IT WORKS</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
The basic idea is to detect when you are compiling exactly the same
|
||||
code a 2nd time and use the previously compiled output. You detect
|
||||
that it is the same code by forming a hash of:
|
||||
<p>
|
||||
<ul>
|
||||
<li> the pre-processor output from running the compiler with -E
|
||||
<li> the command line options
|
||||
<li> the real compilers size and modification time
|
||||
<li> any stderr output generated by the compiler
|
||||
</ul>
|
||||
<p>
|
||||
These are hashed using md4 (a strong hash) and a cache file is formed
|
||||
based on that hash result. When the same compilation is done a second
|
||||
time ccache is able to supply the correct compiler output (including
|
||||
all warnings etc) from the cache.
|
||||
<p>
|
||||
ccache has been carefully written to always produce exactly the same
|
||||
compiler output that you would get without the cache. If you ever
|
||||
discover a case where ccache changes the output of your compiler then
|
||||
please let me know.
|
||||
<p>
|
||||
<H2><a name="CCache_nn13">20.12 USING CCACHE WITH DISTCC</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
distcc is a very useful program for distributing compilation across a
|
||||
range of compiler servers. It is often useful to combine distcc with
|
||||
ccache, so that compiles that are done are sped up by distcc, but that
|
||||
ccache avoids the compile completely where possible.
|
||||
<p>
|
||||
To use distcc with ccache I recommend using the CCACHE_PREFIX
|
||||
option. You just need to set the environment variable CCACHE_PREFIX to
|
||||
'distcc' and ccache will prefix the command line used with the
|
||||
compiler with the command 'distcc'.
|
||||
<p>
|
||||
<H2><a name="CCache_nn14">20.13 SHARING A CACHE</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
A group of developers can increase the cache hit rate by sharing a
|
||||
cache directory. The hard links however cause unwanted side effects,
|
||||
as all links to a cached file share the file's modification timestamp.
|
||||
This results in false dependencies to be triggered by timestamp-based
|
||||
build systems whenever another user links to an existing
|
||||
file. Typically, users will see that their libraries and binaries are
|
||||
relinked without reason. To share a cache without side effects, the
|
||||
following conditions need to be met:
|
||||
<p>
|
||||
<ul>
|
||||
<li> Use the same <strong>CCACHE_DIR</strong> environment variable setting
|
||||
<li> Unset the <strong>CCACHE_HARDLINK</strong> environment variable
|
||||
<li> Make sure everyone sets the CCACHE_UMASK environment variable
|
||||
to 002, this ensures that cached files are accessible to everyone in
|
||||
the group.
|
||||
<li> Make sure that all users have write permission in the entire
|
||||
cache directory (and that you trust all users of the shared cache).
|
||||
<li> Make sure that the setgid bit is set on all directories in the
|
||||
cache. This tells the filesystem to inherit group ownership for new
|
||||
directories. The command "chmod g+s `find $CCACHE_DIR -type d`" might
|
||||
be useful for this.
|
||||
<li> Set <strong>CCACHE_NOCOMPRESS</strong> for all users, if there are users with
|
||||
versions of ccache that do not support compression.
|
||||
</ul>
|
||||
<p>
|
||||
<H2><a name="CCache_nn15">20.14 HISTORY</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
ccache was inspired by the compilercache shell script written
|
||||
by Erik Thiele and I would like to thank him for an excellent piece of
|
||||
work. See
|
||||
<a href="http://www.erikyyy.de/compilercache/">http://www.erikyyy.de/compilercache/</a>
|
||||
for the Erik's scripts.
|
||||
ccache-swig is a port of the original ccache with support added for use
|
||||
with SWIG.
|
||||
<p>
|
||||
I wrote ccache because I wanted to get a bit more speed out of a
|
||||
compiler cache and I wanted to remove some of the limitations of the
|
||||
shell-script version.
|
||||
<p>
|
||||
<H2><a name="CCache_nn16">20.15 DIFFERENCES FROM COMPILERCACHE</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
The biggest differences between Erik's compilercache script and ccache
|
||||
are:
|
||||
<ul>
|
||||
<li> ccache is written in C, which makes it a bit faster (calling out to
|
||||
external programs is mostly what slowed down the scripts).
|
||||
<li> ccache can automatically find the real compiler
|
||||
<li> ccache keeps statistics on hits/misses
|
||||
<li> ccache can do automatic cache management
|
||||
<li> ccache can cache compiler output that includes warnings. In many
|
||||
cases this gives ccache a much higher cache hit rate.
|
||||
<li> ccache can handle a much wider ranger of compiler options
|
||||
<li> ccache avoids a double call to cpp on a cache miss
|
||||
</ul>
|
||||
<p>
|
||||
<H2><a name="CCache_nn17">20.16 CREDITS</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
Thanks to the following people for their contributions to ccache
|
||||
<ul>
|
||||
<li> Erik Thiele for the original compilercache script
|
||||
<li> Luciano Rocha for the idea of compiling the pre-processor output
|
||||
to avoid a 2nd cpp pass
|
||||
<li> Paul Russell for many suggestions and the debian packaging
|
||||
</ul>
|
||||
<p>
|
||||
<H2><a name="CCache_nn18">20.17 AUTHOR</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
ccache was written by Andrew Tridgell
|
||||
<a href="https://www.samba.org/~tridge/">https://www.samba.org/~tridge/</a>.
|
||||
ccache was adapted to create ccache-swig for use with SWIG by William Fulton.
|
||||
<p>
|
||||
If you wish to report a problem or make a suggestion then please email
|
||||
the SWIG developers on the swig-devel mailing list, see
|
||||
<a href="http://www.swig.org/mail.html">http://www.swig.org/mail.html</a>
|
||||
<p>
|
||||
ccache is released under the GNU General Public License version 2 or
|
||||
later. Please see the file COPYING for license details.
|
||||
<p>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,60 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and C++14</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<H1><a name="CPlusPlus14">8 SWIG and C++14</a></H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#CPlusPlus14_introduction">Introduction</a>
|
||||
<li><a href="#CPlusPlus14_core_language_changes">Core language changes</a>
|
||||
<ul>
|
||||
<li><a href="#CPlusPlus14_binary_literals">Binary integer literals</a>
|
||||
</ul>
|
||||
<li><a href="#CPlusPlus14_standard_library_changes">Standard library changes</a>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<H2><a name="CPlusPlus14_introduction">8.1 Introduction</a></H2>
|
||||
|
||||
|
||||
<p>This chapter gives you a brief overview about the SWIG
|
||||
implementation of the C++14 standard.
|
||||
There isn't much in C++14 that affects SWIG, however, work has only just begun on adding
|
||||
C++14 support.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Compatibility note:</b> SWIG-4.0.0 is the first version to support any C++14 features.
|
||||
</p>
|
||||
|
||||
<H2><a name="CPlusPlus14_core_language_changes">8.2 Core language changes</a></H2>
|
||||
|
||||
|
||||
<H3><a name="CPlusPlus14_binary_literals">8.2.1 Binary integer literals</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
C++14 added binary integer literals and SWIG supports these.
|
||||
Example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
int b = 0b101011;
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<H2><a name="CPlusPlus14_standard_library_changes">8.3 Standard library changes</a></H2>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,109 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and C++17</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<H1><a name="CPlusPlus17">9 SWIG and C++17</a></H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#CPlusPlus17_introduction">Introduction</a>
|
||||
<li><a href="#CPlusPlus17_core_language_changes">Core language changes</a>
|
||||
<ul>
|
||||
<li><a href="#CPlusPlus17_nested_namespaces">Nested namespace definitions</a>
|
||||
<li><a href="#CPlusPlus17_u8_char_literals">UTF-8 character literals</a>
|
||||
<li><a href="#CPlusPlus17_hexadecimal_floating_literals">Hexadecimal floating literals</a>
|
||||
</ul>
|
||||
<li><a href="#CPlusPlus17_standard_library_changes">Standard library changes</a>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<H2><a name="CPlusPlus17_introduction">9.1 Introduction</a></H2>
|
||||
|
||||
|
||||
<p>This chapter gives you a brief overview about the SWIG
|
||||
implementation of the C++17 standard.
|
||||
There isn't much in C++17 that affects SWIG, however, work has only just begun on adding
|
||||
C++17 support.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Compatibility note:</b> SWIG-4.0.0 is the first version to support any C++17 features.
|
||||
</p>
|
||||
|
||||
<H2><a name="CPlusPlus17_core_language_changes">9.2 Core language changes</a></H2>
|
||||
|
||||
|
||||
<H3><a name="CPlusPlus17_nested_namespaces">9.2.1 Nested namespace definitions</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
C++17 offers a more concise syntax for defining namespaces.
|
||||
SWIG has support for nested namespace definitions such as:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
namespace A::B::C {
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
This is the equivalent to the C++98 namespace definitions:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
namespace A {
|
||||
namespace B {
|
||||
namespace C {
|
||||
...
|
||||
}
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<H3><a name="CPlusPlus17_u8_char_literals">9.2.2 UTF-8 character literals</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
C++17 added UTF-8 (u8) character literals.
|
||||
These are of type char.
|
||||
Example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
char a = u8'a';
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<H3><a name="CPlusPlus17_hexadecimal_floating_literals">9.2.3 Hexadecimal floating literals</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
C++17 added hexadecimal floating literals.
|
||||
For example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
double f = 0xF.68p2;
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<H2><a name="CPlusPlus17_standard_library_changes">9.3 Standard library changes</a></H2>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,597 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and Chicken</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
|
||||
<H1><a name="Chicken">23 SWIG and Chicken</a></H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#Chicken_nn2">Preliminaries</a>
|
||||
<ul>
|
||||
<li><a href="#Chicken_nn3">Running SWIG in C mode</a>
|
||||
<li><a href="#Chicken_nn4">Running SWIG in C++ mode</a>
|
||||
</ul>
|
||||
<li><a href="#Chicken_nn5">Code Generation</a>
|
||||
<ul>
|
||||
<li><a href="#Chicken_nn6">Naming Conventions</a>
|
||||
<li><a href="#Chicken_nn7">Modules</a>
|
||||
<li><a href="#Chicken_nn8">Constants and Variables</a>
|
||||
<li><a href="#Chicken_nn9">Functions</a>
|
||||
<li><a href="#Chicken_nn10">Exceptions</a>
|
||||
</ul>
|
||||
<li><a href="#Chicken_nn11">TinyCLOS</a>
|
||||
<li><a href="#Chicken_nn12">Linkage</a>
|
||||
<ul>
|
||||
<li><a href="#Chicken_nn13">Static binary or shared library linked at compile time</a>
|
||||
<li><a href="#Chicken_nn14">Building chicken extension libraries</a>
|
||||
<li><a href="#Chicken_nn15">Linking multiple SWIG modules with TinyCLOS</a>
|
||||
</ul>
|
||||
<li><a href="#Chicken_nn16">Typemaps</a>
|
||||
<li><a href="#Chicken_nn17">Pointers</a>
|
||||
<ul>
|
||||
<li><a href="#Chicken_collection">Garbage collection</a>
|
||||
</ul>
|
||||
<li><a href="#Chicken_nn18">Unsupported features and known problems</a>
|
||||
<ul>
|
||||
<li><a href="#Chicken_nn19">TinyCLOS problems with Chicken version <= 1.92</a>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
This chapter describes SWIG's support of CHICKEN. CHICKEN is a
|
||||
Scheme-to-C compiler supporting most of the language features as
|
||||
defined in the <i>Revised^5 Report on Scheme</i>. Its main
|
||||
attributes are that it
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li>generates portable C code</li>
|
||||
<li>includes a customizable interpreter</li>
|
||||
<li>links to C libraries with a simple Foreign Function Interface</li>
|
||||
<li>supports full tail-recursion and first-class continuations</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
When confronted with a large C library, CHICKEN users can use
|
||||
SWIG to generate CHICKEN wrappers for the C library. However,
|
||||
the real advantages of using SWIG with CHICKEN are its
|
||||
<strong>support for C++</strong> -- object-oriented code is
|
||||
difficult to wrap by hand in CHICKEN -- and its <strong>typed
|
||||
pointer representation</strong>, essential for C and C++
|
||||
libraries involving structures or classes.
|
||||
|
||||
</p>
|
||||
|
||||
<H2><a name="Chicken_nn2">23.1 Preliminaries</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
CHICKEN support was introduced to SWIG in version 1.3.18. SWIG
|
||||
relies on some recent additions to CHICKEN, which are only
|
||||
present in releases of CHICKEN with version number
|
||||
<strong>greater than or equal to 1.89</strong>.
|
||||
To use a chicken version between 1.40 and 1.89, see the <a href="#Chicken_collection">Garbage collection</a>
|
||||
section below.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You may want to look at any of the examples in Examples/chicken/
|
||||
directory for the basic steps to run SWIG CHICKEN.
|
||||
</p>
|
||||
|
||||
<H3><a name="Chicken_nn3">23.1.1 Running SWIG in C mode</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
To run SWIG CHICKEN in C mode, use
|
||||
the -chicken option.
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>% swig -chicken example.i</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
To allow the wrapper to take advantage of future CHICKEN code
|
||||
generation improvements, part of the wrapper is direct CHICKEN
|
||||
function calls (<tt>example_wrap.c</tt>) and part is CHICKEN
|
||||
Scheme (<tt>example.scm</tt>). The basic Scheme code must
|
||||
be compiled to C using your system's CHICKEN compiler or
|
||||
both files can be compiled directly using the much simpler <tt>csc</tt>.
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
% chicken example.scm -output-file oexample.c
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
So for the C mode of SWIG CHICKEN, <tt>example_wrap.c</tt> and
|
||||
<tt>oexample.c</tt> are the files that must be compiled to
|
||||
object files and linked into your project.
|
||||
</p>
|
||||
|
||||
<H3><a name="Chicken_nn4">23.1.2 Running SWIG in C++ mode</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
To run SWIG CHICKEN in C++ mode, use
|
||||
the -chicken -c++ option.
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>% swig -chicken -c++ example.i</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
This will generate <tt>example_wrap.cxx</tt> and
|
||||
<tt>example.scm</tt>. The basic Scheme code must be
|
||||
compiled to C using your system's CHICKEN compiler or
|
||||
both files can be compiled directly using the much simpler <tt>csc</tt>.
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>% chicken example.scm -output-file oexample.c</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
So for the C++ mode of SWIG CHICKEN, <tt>example_wrap.cxx</tt>
|
||||
and <tt>oexample.c</tt> are the files that must be compiled to
|
||||
object files and linked into your project.
|
||||
</p>
|
||||
|
||||
<H2><a name="Chicken_nn5">23.2 Code Generation</a></H2>
|
||||
|
||||
|
||||
<H3><a name="Chicken_nn6">23.2.1 Naming Conventions</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Given a C variable, function or constant declaration named
|
||||
<tt>Foo_Bar</tt>, the declaration will be available
|
||||
in CHICKEN as an identifier ending with
|
||||
<tt>Foo-Bar</tt>. That is, an underscore is converted
|
||||
to a dash.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You may control what the CHICKEN identifier will be by using the
|
||||
<tt>%rename</tt> SWIG directive in the SWIG interface file.
|
||||
</p>
|
||||
|
||||
<H3><a name="Chicken_nn7">23.2.2 Modules</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
The name of the module must be declared one of two ways:
|
||||
<ul>
|
||||
<li>Placing <tt>%module example</tt> in the SWIG interface
|
||||
file.</li>
|
||||
<li>Using <tt>-module example</tt> on the SWIG command
|
||||
line.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
The generated example.scm file then exports <code>(declare (unit modulename))</code>.
|
||||
If you do not want SWIG to export the <code>(declare (unit modulename))</code>, pass
|
||||
the -nounit option to SWIG.
|
||||
|
||||
<p>
|
||||
CHICKEN will be able to access the module using the <code>(declare
|
||||
(uses <i>modulename</i>))</code> CHICKEN Scheme form.
|
||||
</p>
|
||||
|
||||
<H3><a name="Chicken_nn8">23.2.3 Constants and Variables</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Constants may be created using any of the four constructs in
|
||||
the interface file:
|
||||
</p>
|
||||
<ol>
|
||||
<li><code>#define MYCONSTANT1 ...</code></li>
|
||||
<li><code>%constant int MYCONSTANT2 = ...</code></li>
|
||||
<li><code>const int MYCONSTANT3 = ...</code></li>
|
||||
<li><code>enum { MYCONSTANT4 = ... };</code></li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
In all cases, the constants may be accessed from within CHICKEN
|
||||
using the form <tt>(MYCONSTANT1)</tt>; that is, the constants
|
||||
may be accessed using the read-only parameter form.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Variables are accessed using the full parameter form.
|
||||
For example, to set the C variable "int my_variable;", use the
|
||||
Scheme form <tt>(my-variable 2345)</tt>. To get the C variable,
|
||||
use <tt>(my-variable)</tt>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <tt>%feature("constasvar")</tt> can be applied to any constant
|
||||
or immutable variable. Instead of exporting the constant as
|
||||
a function that must be called, the constant will appear as a
|
||||
scheme variable. This causes the generated .scm file to just contain the code
|
||||
<tt>(set! MYCONSTANT1 (MYCONSTANT1))</tt>. See
|
||||
<a href="Customization.html#Customization_features">Features and the %feature directive</a>
|
||||
for info on how to apply the %feature.
|
||||
</p>
|
||||
|
||||
<H3><a name="Chicken_nn9">23.2.4 Functions</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
C functions declared in the SWIG interface file will have
|
||||
corresponding CHICKEN Scheme procedures. For example, the C
|
||||
function "int sqrt(double x);" will be available using the
|
||||
Scheme form <tt>(sqrt 2345.0)</tt>. A <code>void</code> return
|
||||
value will give C_SCHEME_UNDEFINED as a result.
|
||||
</p>
|
||||
<p>
|
||||
A function may return more than one value by using the
|
||||
<code>OUTPUT</code> specifier (see Lib/chicken/typemaps.i).
|
||||
They will be returned as multiple values using <code>(values)</code> if there is more than one
|
||||
result (that is, a non-void return value and at least one argout
|
||||
parameter, or a void return value and at least two argout
|
||||
parameters). The return values can then be accessed with <code>(call-with-values)</code>.
|
||||
</p>
|
||||
|
||||
<H3><a name="Chicken_nn10">23.2.5 Exceptions</a></H3>
|
||||
|
||||
|
||||
<p>The SWIG chicken module has support for exceptions thrown from
|
||||
C or C++ code to be caught in scheme.
|
||||
See <a href="Customization.html#Customization_exception">Exception handling with %exception</a>
|
||||
for more information about declaring exceptions in the interface file.
|
||||
</p>
|
||||
|
||||
<p>Chicken supports both the <code>SWIG_exception(int code, const char *msg)</code> interface
|
||||
as well as a <code>SWIG_ThrowException(C_word val)</code> function for throwing exceptions from
|
||||
inside the %exception blocks. <code>SWIG_exception</code> will throw a list consisting of the code
|
||||
(as an integer) and the message. Both of these will throw an exception using <code>(abort)</code>,
|
||||
which can be handled by <code>(handle-exceptions)</code>. See
|
||||
the Chicken manual on Exceptions
|
||||
and <a href="http://srfi.schemers.org/srfi-12/srfi-12.html">SFRI-12</a>. Since the exception values are thrown
|
||||
directly, if <code>(condition-case)</code> is used to catch an exception the exception will come through in the <code>val ()</code> case.
|
||||
</p>
|
||||
|
||||
<p>The following simple module</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%module exception_test
|
||||
|
||||
%inline %{
|
||||
void test_throw(int i) throws (int) {
|
||||
if (i == 1) throw 15;
|
||||
}
|
||||
%}
|
||||
</pre></div>
|
||||
|
||||
<p>could be run with</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
(handle-exceptions exvar
|
||||
(if (= exvar 15)
|
||||
(print "Correct!")
|
||||
(print "Threw something else " exvar))
|
||||
(test-throw 1))
|
||||
</pre></div>
|
||||
|
||||
|
||||
<H2><a name="Chicken_nn11">23.3 TinyCLOS</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
The author of TinyCLOS, Gregor Kiczales, describes TinyCLOS as:
|
||||
"Tiny CLOS is a Scheme implementation of a 'kernelized' CLOS, with a
|
||||
metaobject protocol. The implementation is even simpler than
|
||||
the simple CLOS found in 'The Art of the Metaobject Protocol',
|
||||
weighing in at around 850 lines of code, including (some)
|
||||
comments and documentation."
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Almost all good Scheme books describe how to use metaobjects and
|
||||
generic procedures to implement an object-oriented Scheme
|
||||
system. Please consult a Scheme book if you are unfamiliar
|
||||
with the concept.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
CHICKEN has a modified version of TinyCLOS, which SWIG CHICKEN
|
||||
uses if the -proxy argument is given. If -proxy is passed, then
|
||||
the generated example.scm file will contain TinyCLOS class definitions.
|
||||
A class named Foo is declared as <Foo>, and each member variable
|
||||
is allocated a slot. Member functions are exported as generic functions.
|
||||
|
||||
<p>
|
||||
|
||||
Primitive symbols and functions (the interface that would be presented if
|
||||
-proxy was not passed) are hidden and no longer accessible. If the -unhideprimitive
|
||||
command line argument is passed to SWIG, then the primitive symbols will be
|
||||
available, but each will be prefixed by the string "primitive:"
|
||||
|
||||
<p>
|
||||
|
||||
The exported symbol names can be controlled with the -closprefix and -useclassprefix arguments.
|
||||
If -useclassprefix is passed to SWIG, every member function will be generated with the class name
|
||||
as a prefix. If the -closprefix mymod: argument is passed to SWIG, then the exported functions will
|
||||
be prefixed by the string "mymod:". If -useclassprefix is passed, -closprefix is ignored.
|
||||
|
||||
</p>
|
||||
|
||||
<H2><a name="Chicken_nn12">23.4 Linkage</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
Please refer to <em>CHICKEN - A practical and portable Scheme
|
||||
system - User's manual</em> for detailed help on how to link
|
||||
object files to create a CHICKEN Scheme program. Briefly, to
|
||||
link object files, be sure to add <tt>`chicken-config
|
||||
-extra-libs -libs`</tt> or <tt>`chicken-config -shared
|
||||
-extra-libs -libs`</tt>to your linker options. Use the
|
||||
<tt>-shared</tt> option if you want to create a dynamically
|
||||
loadable module. You might also want to use the much simpler
|
||||
<tt>csc</tt> or <tt>csc.bat</tt>.
|
||||
</p>
|
||||
|
||||
<p>Each scheme file that is generated
|
||||
by SWIG contains <code>(declare (uses <i>modname</i>))</code>. This means that to load the
|
||||
module from scheme code, the code must include <code>(declare (uses <i>modname</i>))</code>.
|
||||
</p>
|
||||
|
||||
|
||||
<H3><a name="Chicken_nn13">23.4.1 Static binary or shared library linked at compile time</a></H3>
|
||||
|
||||
|
||||
<p>We can easily use csc to build a static binary.</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ swig -chicken example.i
|
||||
$ csc -v example.scm example_impl.c example_wrap.c test_script.scm -o example
|
||||
$ ./example
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>Similar to the above, any number of <tt>module.scm</tt> files could be compiled
|
||||
into a shared library, and then that shared library linked when compiling the
|
||||
main application.</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ swig -chicken example.i
|
||||
$ csc -sv example.scm example_wrap.c example_impl.c -o example.so
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>The <tt>example.so</tt> file can then linked with <tt>test_script.scm</tt> when it
|
||||
is compiled, in which case <tt>test_script.scm</tt> must have <code>(declare (uses example))</code>.
|
||||
Multiple SWIG modules could have been linked into <tt>example.so</tt> and each
|
||||
one accessed with a <code>(declare (uses ... ))</code>.
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ csc -v test_script.scm -lexample
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>An alternative is that the test_script.scm can have the code <code>(load-library 'example "example.so")</code>,
|
||||
in which case the test script does not need to be linked with example.so. The test_script.scm file can then
|
||||
be run with <tt>csi</tt>.
|
||||
</p>
|
||||
|
||||
<H3><a name="Chicken_nn14">23.4.2 Building chicken extension libraries</a></H3>
|
||||
|
||||
|
||||
<p>Building a shared library like in the above section only works if the library
|
||||
is linked at compile time with a script containing <code>(declare (uses ...))</code> or is
|
||||
loaded explicitly with <code>(load-library 'example "example.so")</code>. It is
|
||||
not the format that CHICKEN expects for extension libraries and eggs. The problem is the
|
||||
<code>(declare (unit <i>modname</i>))</code> inside the <tt>modname.scm</tt> file. There are
|
||||
two possible solutions to this.</p>
|
||||
|
||||
<p>First, SWIG accepts a <tt>-nounit</tt> argument, in which case the <code>(declare (unit <i>modname</i>))</code>
|
||||
is not generated. Then, the <tt>modname.scm</tt> and <tt>modname_wrap.c</tt> files <b>must</b> be compiled into
|
||||
their own shared library.</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ csc -sv modname.scm modname_wrap.c modname_impl.c -o modname.so
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>This library can then be loaded by scheme code with the <code>(require 'modname)</code> function.
|
||||
See the
|
||||
Loading-extension-libraries in the eval unit inside the CHICKEN manual for more information.</p>
|
||||
|
||||
<p>Another alternative is to run SWIG normally and create a scheme file that contains <code>(declare (uses <i>modname</i>))</code>
|
||||
and then compile that file into the shared library as well. For example, inside the <tt>mod_load.scm</tt> file,</p>
|
||||
|
||||
<div class="targetlang">
|
||||
<pre>
|
||||
(declare (uses mod1))
|
||||
(declare (uses mod2))
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>Which would then be compiled with</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ swig -chicken mod1.i
|
||||
$ swig -chicken mod2.i
|
||||
$ csc -sv mod_load.scm mod1.scm mod2.scm mod1_wrap.c mod2_wrap.c mod1_impl.c mod2_impl.c -o mod.so
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>Then the extension library can be loaded with <code>(require 'mod)</code>. As we can see here,
|
||||
<tt>mod_load.scm</tt> contains the code that gets executed when the module is loaded. All this code
|
||||
does is load both mod1 and mod2. As we can see, this technique is more useful when you want to
|
||||
combine a few SWIG modules into one chicken extension library, especially if modules are related by
|
||||
<code>%import</code></p>
|
||||
|
||||
<p>In either method, the files that are compiled into the shared library could also be
|
||||
packaged into an egg. The <tt>mod1_wrap.c</tt> and <tt>mod2_wrap.c</tt> files that are created by SWIG
|
||||
are stand alone and do not need SWIG to be installed to be compiled. Thus the egg could be
|
||||
distributed and used by anyone, even if SWIG is not installed.</p>
|
||||
|
||||
<p>See the <tt>Examples/chicken/egg</tt> directory in the SWIG source for an example that builds
|
||||
two eggs, one using the first method and one using the second method.</p>
|
||||
|
||||
<H3><a name="Chicken_nn15">23.4.3 Linking multiple SWIG modules with TinyCLOS</a></H3>
|
||||
|
||||
|
||||
<p>Linking together multiple modules that share type information using the <code>%import</code>
|
||||
directive while also using <tt>-proxy</tt> is more complicated. For example, if <tt>mod2.i</tt> imports <tt>mod1.i</tt>, then the
|
||||
<tt>mod2.scm</tt> file contains references to symbols declared in <tt>mod1.scm</tt>,
|
||||
and thus a <code>(declare (uses <i>mod1</i>))</code> or <code>(require '<i>mod1</i>)</code> must be exported
|
||||
to the top of <tt>mod2.scm</tt>. By default, when SWIG encounters an <code>%import "modname.i"</code> directive,
|
||||
it exports <code>(declare (uses <i>modname</i>))</code> into the scm file. This works fine unless mod1 was compiled with
|
||||
the <tt>-nounit</tt> argument or was compiled into an extension library with other modules under a different name.</p>
|
||||
|
||||
<p>One option is to override the automatic generation of <code>(declare (uses mod1))</code>
|
||||
by passing the <tt>-noclosuses</tt> option to SWIG when compiling <tt>mod2.i</tt>.
|
||||
SWIG then provides the <code>%insert(closprefix) %{ %}</code> directive. Any scheme code inside that directive is inserted into the
|
||||
generated .scm file, and if <tt>mod1</tt> was compiled with <tt>-nounit</tt>, the directive should contain <code>(require 'mod1)</code>.
|
||||
This option allows for mixed loading as well, where some modules are imported with <code>(declare (uses <i>modname</i>))</code>
|
||||
(which means they were compiled without -nounit) and some are imported with <code>(require 'modname)</code>.</p>
|
||||
|
||||
<p>The other option is to use the second idea in the above section. Compile all the modules normally, without any
|
||||
<code>%insert(closprefix)</code>, <tt>-nounit</tt>, or <tt>-noclosuses</tt>. Then the modules will import each other correctly
|
||||
with <code>(declare (uses ...))</code>.
|
||||
To create an extension library or an egg, just create a <tt>module_load.scm</tt> file that <code>(declare (uses ...))</code>
|
||||
all the modules.</p>
|
||||
|
||||
<H2><a name="Chicken_nn16">23.5 Typemaps</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
The Chicken module handles all types via typemaps. This information is
|
||||
read from <code>Lib/chicken/typemaps.i</code> and
|
||||
<code>Lib/chicken/chicken.swg</code>.
|
||||
</p>
|
||||
|
||||
<H2><a name="Chicken_nn17">23.6 Pointers</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
For pointer types, SWIG uses CHICKEN tagged pointers.
|
||||
|
||||
A tagged pointer is an ordinary CHICKEN pointer with an
|
||||
extra slot for a void *. With SWIG
|
||||
CHICKEN, this void * is a pointer to a type-info
|
||||
structure. So each pointer used as input or output from
|
||||
the SWIG-generated CHICKEN wrappers will have type
|
||||
information attached to it. This will let the wrappers
|
||||
correctly determine which method should be called
|
||||
according to the object type hierarchy exposed in the SWIG
|
||||
interface files.
|
||||
</p>
|
||||
<p>
|
||||
To construct a Scheme object from a C pointer, the wrapper code
|
||||
calls the function
|
||||
<code>SWIG_NewPointerObj(void *ptr, swig_type_info *type, int owner)</code>,
|
||||
The function that calls <code>SWIG_NewPointerObj</code> must have a variable declared
|
||||
<code>C_word *known_space = C_alloc(C_SIZEOF_SWIG_POINTER);</code>
|
||||
It is ok to call <code>SWIG_NewPointerObj</code> more than once,
|
||||
just make sure known_space has enough space for all the created pointers.
|
||||
</p>
|
||||
<p>
|
||||
To get the pointer represented by a CHICKEN tagged pointer, the
|
||||
wrapper code calls the function
|
||||
<code>SWIG_ConvertPtr(C_word s, void **result, swig_type_info *type, int flags)</code>,
|
||||
passing a pointer to a struct representing the expected pointer
|
||||
type. flags is either zero or SWIG_POINTER_DISOWN (see below).
|
||||
</p>
|
||||
|
||||
<H3><a name="Chicken_collection">23.6.1 Garbage collection</a></H3>
|
||||
|
||||
|
||||
<p>If the owner flag passed to <code>SWIG_NewPointerObj</code> is 1, <code>NewPointerObj</code> will add a
|
||||
finalizer to the type which will call the destructor or delete method of
|
||||
that type. The destructor and delete functions are no longer exported for
|
||||
use in scheme code, instead SWIG and chicken manage pointers.
|
||||
In situations where SWIG knows that a function is returning a type that should
|
||||
be garbage collected, SWIG will automatically set the owner flag to 1. For other functions,
|
||||
the <code>%newobject</code> directive must be specified for functions whose return values
|
||||
should be garbage collected. See
|
||||
<a href="Customization.html#Customization_ownership">Object ownership and %newobject</a> for more information.
|
||||
</p>
|
||||
|
||||
<p>In situations where a C or C++ function will assume ownership of a pointer, and thus
|
||||
chicken should no longer garbage collect it, SWIG provides the <code>DISOWN</code> input typemap.
|
||||
After applying this typemap (see the <a href="Typemaps.html#Typemaps">Typemaps chapter</a> for more information on how to apply typemaps),
|
||||
any pointer that gets passed in will no longer be garbage collected.
|
||||
An object is disowned by passing the <code>SWIG_POINTER_DISOWN</code> flag to <code>SWIG_ConvertPtr</code>.
|
||||
<b>Warning:</b> Since the lifetime of the object is now controlled by the underlying code, the object might
|
||||
get deleted while the scheme code still holds a pointer to it. Further use of this pointer
|
||||
can lead to a crash.
|
||||
</p>
|
||||
|
||||
<p>Adding a finalizer function from C code was added to chicken in the 1.89 release, so garbage collection
|
||||
does not work for chicken versions below 1.89. If you would like the SWIG generated code to work with
|
||||
chicken 1.40 to 1.89, pass the <code>-nocollection</code> argument to SWIG. This will not export code
|
||||
inside the _wrap.c file to register finalizers, and will then export destructor functions which
|
||||
must be called manually.
|
||||
</p>
|
||||
|
||||
<H2><a name="Chicken_nn18">23.7 Unsupported features and known problems</a></H2>
|
||||
|
||||
|
||||
<ul>
|
||||
<li>No director support.</li>
|
||||
<li>No support for c++ standard types like std::vector.</li>
|
||||
<li>The TinyCLOS wrappers for overloaded functions will not work correctly when using
|
||||
<a href="SWIGPlus.html#SWIGPlus_default_args">%feature(compactdefaultargs)</a>.</li>
|
||||
</ul>
|
||||
|
||||
<H3><a name="Chicken_nn19">23.7.1 TinyCLOS problems with Chicken version <= 1.92</a></H3>
|
||||
|
||||
|
||||
<p>In Chicken versions equal to or below 1.92, TinyCLOS has a limitation such that generic methods do not properly work on methods
|
||||
with different number of specializers: TinyCLOS assumes that every method added to a generic function
|
||||
will have the same number of specializers. SWIG generates functions with different lengths of specializers
|
||||
when C/C++ functions are overloaded. For example, the code</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
class Foo {};
|
||||
int foo(int a, Foo *b);
|
||||
int foo(int a);
|
||||
</pre></div>
|
||||
|
||||
<p>will produce scheme code</p>
|
||||
|
||||
<div class="targetlang">
|
||||
<pre>
|
||||
(define-method (foo (arg0 <top>) (arg1 <Foo>)) (<i>call primitive function</i>))
|
||||
(define-method (foo (arg0 <top>)) (<i>call primitive function</i>))
|
||||
</pre></div>
|
||||
|
||||
<p>Using unpatched TinyCLOS, the second <code>(define-method)</code> will replace the first one,
|
||||
so calling <code>(foo 3 f)</code> will produce an error.</p>
|
||||
|
||||
<p>There are three solutions to this. The easist is to upgrade to the latest Chicken version. Otherwise, the
|
||||
file <tt>Lib/chicken/tinyclos-multi-generic.patch</tt> in the SWIG source contains a patch against
|
||||
tinyclos.scm inside the 1.92 chicken source to add support into TinyCLOS for multi-argument generics. (This patch was accepted into Chicken)
|
||||
This requires chicken to be rebuilt and custom install of chicken. An alternative is the <tt>Lib/chicken/multi-generic.scm</tt>
|
||||
file in the SWIG source. This file can be loaded after TinyCLOS is loaded, and it will override some functions
|
||||
inside TinyCLOS to correctly support multi-argument generics. Please see the comments at the top of both files for more information.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,275 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Contract Checking</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<H1><a name="Contract">15 Contracts</a></H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#Contract_nn2">The %contract directive</a>
|
||||
<li><a href="#Contract_nn3">%contract and classes</a>
|
||||
<li><a href="#Contract_nn4">Constant aggregation and %aggregate_check</a>
|
||||
<li><a href="#Contract_nn5">Notes</a>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
A common problem that arises when wrapping C libraries is that of maintaining
|
||||
reliability and checking for errors. The fact of the matter is that many
|
||||
C programs are notorious for not providing error checks. Not only that,
|
||||
when you expose the internals of an application as a library, it
|
||||
often becomes possible to crash it simply by providing bad inputs or
|
||||
using it in a way that wasn't intended.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This chapter describes SWIG's support for software contracts. In the context
|
||||
of SWIG, a contract can be viewed as a runtime constraint that is attached
|
||||
to a declaration. For example, you can easily attach argument checking rules,
|
||||
check the output values of a function and more.
|
||||
When one of the rules is violated by a script, a runtime exception is
|
||||
generated rather than having the program continue to execute.
|
||||
</p>
|
||||
|
||||
<H2><a name="Contract_nn2">15.1 The %contract directive</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
Contracts are added to a declaration using the %contract directive. Here
|
||||
is a simple example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%contract sqrt(double x) {
|
||||
require:
|
||||
x >= 0;
|
||||
ensure:
|
||||
sqrt >= 0;
|
||||
}
|
||||
|
||||
...
|
||||
double sqrt(double);
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
In this case, a contract is being added to the <tt>sqrt()</tt> function.
|
||||
The <tt>%contract</tt> directive must always appear before the declaration
|
||||
in question. Within the contract there are two sections, both of which
|
||||
are optional. The <tt>require:</tt>
|
||||
section specifies conditions that must hold before the function is called.
|
||||
Typically, this is used to check argument values. The <tt>ensure:</tt> section
|
||||
specifies conditions that must hold after the function is called. This is
|
||||
often used to check return values or the state of the program. In both
|
||||
cases, the conditions that must hold must be specified as boolean expressions.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In the above example, we're simply making sure that sqrt() returns a non-negative
|
||||
number (if it didn't, then it would be broken in some way).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Once a contract has been specified, it modifies the behavior of the
|
||||
resulting module. For example:
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
>>> example.sqrt(2)
|
||||
1.4142135623730951
|
||||
>>> example.sqrt(-2)
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in ?
|
||||
RuntimeError: Contract violation: require: (arg1>=0)
|
||||
>>>
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<H2><a name="Contract_nn3">15.2 %contract and classes</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
The <tt>%contract</tt> directive can also be applied to class methods and constructors. For example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%contract Foo::bar(int x, int y) {
|
||||
require:
|
||||
x > 0;
|
||||
ensure:
|
||||
bar > 0;
|
||||
}
|
||||
|
||||
%contract Foo::Foo(int a) {
|
||||
require:
|
||||
a > 0;
|
||||
}
|
||||
|
||||
class Foo {
|
||||
public:
|
||||
Foo(int);
|
||||
int bar(int, int);
|
||||
};
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The way in which <tt>%contract</tt> is applied is exactly the same as the <tt>%feature</tt> directive.
|
||||
Thus, any contract that you specified for a base class will also be attached to inherited methods. For example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
class Spam : public Foo {
|
||||
public:
|
||||
int bar(int, int); // Gets contract defined for Foo::bar(int, int)
|
||||
};
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
In addition to this, separate contracts can be applied to both the base class and a derived class. For example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%contract Foo::bar(int x, int) {
|
||||
require:
|
||||
x > 0;
|
||||
}
|
||||
|
||||
%contract Spam::bar(int, int y) {
|
||||
require:
|
||||
y > 0;
|
||||
}
|
||||
|
||||
class Foo {
|
||||
public:
|
||||
int bar(int, int); // Gets Foo::bar contract.
|
||||
};
|
||||
|
||||
class Spam : public Foo {
|
||||
public:
|
||||
int bar(int, int); // Gets Foo::bar and Spam::bar contract
|
||||
};
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
When more than one contract is applied, the conditions specified in a
|
||||
"require:" section are combined together using a logical-AND operation.
|
||||
In other words conditions specified for the base class and conditions
|
||||
specified for the derived class all must hold. In the above example,
|
||||
this means that both the arguments to <tt>Spam::bar</tt> must be positive.
|
||||
</p>
|
||||
|
||||
<H2><a name="Contract_nn4">15.3 Constant aggregation and %aggregate_check</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
Consider an interface file that contains the following code:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
#define UP 1
|
||||
#define DOWN 2
|
||||
#define RIGHT 3
|
||||
#define LEFT 4
|
||||
|
||||
void move(SomeObject *, int direction, int distance);
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
One thing you might want to do is impose a constraint on the direction parameter to
|
||||
make sure it's one of a few accepted values. To do that, SWIG provides an easy to
|
||||
use macro %aggregate_check() that works like this:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%aggregate_check(int, check_direction, UP, DOWN, LEFT, RIGHT);
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
This merely defines a utility function of the form
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
int check_direction(int x);
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
That checks the argument x to see if it is one of the values listed. This utility
|
||||
function can be used in contracts. For example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%aggregate_check(int, check_direction, UP, DOWN, RIGHT, LEFT);
|
||||
|
||||
%contract move(SomeObject *, int direction, in) {
|
||||
require:
|
||||
check_direction(direction);
|
||||
}
|
||||
|
||||
#define UP 1
|
||||
#define DOWN 2
|
||||
#define RIGHT 3
|
||||
#define LEFT 4
|
||||
|
||||
void move(SomeObject *, int direction, int distance);
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Alternatively, it can be used in typemaps and other directives. For example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%aggregate_check(int, check_direction, UP, DOWN, RIGHT, LEFT);
|
||||
|
||||
%typemap(check) int direction {
|
||||
if (!check_direction($1)) SWIG_exception(SWIG_ValueError, "Bad direction");
|
||||
}
|
||||
|
||||
#define UP 1
|
||||
#define DOWN 2
|
||||
#define RIGHT 3
|
||||
#define LEFT 4
|
||||
|
||||
void move(SomeObject *, int direction, int distance);
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Regrettably, there is no automatic way to perform similar checks with enums values. Maybe in a future
|
||||
release.
|
||||
</p>
|
||||
|
||||
<H2><a name="Contract_nn5">15.4 Notes</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
Contract support was implemented by Songyan (Tiger) Feng and first appeared
|
||||
in SWIG-1.3.20.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,458 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and D</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF">
|
||||
<H1><a name="D">23 SWIG and D</a></H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#D_introduction">Introduction</a>
|
||||
<li><a href="#D_command_line_invocation">Command line invocation</a>
|
||||
<li><a href="#D_typemaps">Typemaps</a>
|
||||
<ul>
|
||||
<li><a href="#D_typemap_name_comparison">C# <-> D name comparison</a>
|
||||
<li><a href="#D_ctype_imtype_dtype">ctype, imtype, dtype</a>
|
||||
<li><a href="#D_in_out_directorin_direcetorout">in, out, directorin, directorout</a>
|
||||
<li><a href="#D_din_dout_ddirectorin_ddirectorout">din, dout, ddirectorin, ddirectorout</a>
|
||||
<li><a href="#D_typecheck_typemaps">typecheck typemaps</a>
|
||||
<li><a href="#D_code_injection_typemaps">Code injection typemaps</a>
|
||||
<li><a href="#D_special_variables">Special variable macros</a>
|
||||
</ul>
|
||||
<li><a href="#D_features">D and %feature</a>
|
||||
<li><a href="#D_pragmas">Pragmas</a>
|
||||
<li><a href="#D_exceptions">D Exceptions</a>
|
||||
<li><a href="#D_directors">D Directors</a>
|
||||
<li><a href="#D_other_features">Other features</a>
|
||||
<ul>
|
||||
<li><a href="#D_nspace">Extended namespace support (nspace)</a>
|
||||
<li><a href="#D_native_pointer_support">Native pointer support</a>
|
||||
<li><a href="#D_operator_overloading">Operator overloading</a>
|
||||
<li><a href="#D_test_suite">Running the test-suite</a>
|
||||
</ul>
|
||||
<li><a href="#D_typemap_examples">D Typemap examples</a>
|
||||
<li><a href="#D_planned_features">Work in progress and planned features</a>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<H2><a name="D_introduction">23.1 Introduction</a></H2>
|
||||
|
||||
|
||||
<p>From the <a href="http://www.digitalmars.com/d/">D Programming Language</a> web site: <em>D is a systems programming language. Its focus is on combining the power and high performance of C and C++ with the programmer productivity of modern languages like Ruby and Python. [...] The D language is statically typed and compiles directly to machine code.</em> As such, it is not very surprising that D is able to directly <a href="http://www.digitalmars.com/d/1.0/interfaceToC.html">interface with C libraries</a>. Why would a SWIG module for D be needed then in the first place?</p>
|
||||
|
||||
<p>Well, besides the obvious downside that the C header files have to be manually converted to D modules for this to work, there is one major inconvenience with this approach: D code usually is on a higher abstraction level than C, and many of the features that make D interesting are simply not available when dealing with C libraries, requiring you e.g. to manually convert strings between pointers to <tt>\0</tt>-terminated char arrays and D char arrays, making the algorithms from the D2 standard library unusable with C arrays and data structures, and so on.</p>
|
||||
|
||||
<p>While these issues can be worked around relatively easy by hand-coding a thin wrapper layer around the C library in question, there is another issue where writing wrapper code per hand is not feasible: C++ libraries. D did not support interfacing to C++ in version 1 at all, and even if <tt>extern(C++)</tt> has been added to D2, the support is still very limited, and a custom wrapper layer is still required in many cases. </p>
|
||||
|
||||
<p>To help addressing these issues, the SWIG C# module has been forked to support D. Is has evolved quite a lot since then, but there are still many similarities, so if you do not find what you are looking for on this page, it might be worth having a look at the chapter on <a href="CSharp.html#CSharp">C#</a> (and also on <a href="Java.html#Java">Java</a>, since the C# module was in turn forked from it).</p>
|
||||
|
||||
|
||||
<H2><a name="D_command_line_invocation">23.2 Command line invocation</a></H2>
|
||||
|
||||
|
||||
<p>To activate the D module, pass the <tt>-d</tt> option to SWIG at the command line. The same standard command line options as with any other language module are available, plus the following D specific ones:</p>
|
||||
|
||||
<dl>
|
||||
<dt><tt>-d2</tt></dt>
|
||||
<dd>
|
||||
<p>By default, SWIG generates code for D1/Tango. Use the <tt>-d2</tt> flag to target D2/Phobos instead.</p>
|
||||
</dd>
|
||||
|
||||
<dt><a name="D_splitproxy"></a><tt>-splitproxy</tt></dt>
|
||||
<dd>
|
||||
<p>By default, SWIG generates two D modules: the <em>proxy</em> module, named like the source module (either specified via the <tt>%module</tt> directive or via the <tt>module</tt> command line option), which contains all the proxy classes, functions, enums, etc., and the <em>intermediary</em> module (named like the proxy module, but suffixed with <tt>_im</tt>), which contains all the <tt>extern(C)</tt> function declarations and other private parts only used internally by the proxy module.</p>
|
||||
<p>If the split proxy mode is enabled by passing this option at the command line, all proxy classes and enums are emitted to their own D module instead. The main proxy module only contains free functions and constants in this case.</p>
|
||||
</dd>
|
||||
|
||||
<dt><tt>-package <pkg></tt></dt>
|
||||
<dd>
|
||||
<p>By default, the proxy D modules and the intermediary D module are written to the root package. Using this option, you can specify another target package instead.</p>
|
||||
</dd>
|
||||
|
||||
<dt><tt>-wrapperlibrary <wl></tt></dt>
|
||||
<dd>
|
||||
<p>The code SWIG generates to dynamically load the C/C++ wrapper layer looks for a library called <tt>$module_wrap</tt> by default. With this option, you can override the name of the file the wrapper code loads at runtime (the <tt>lib</tt> prefix and the suffix for shared libraries are appended automatically, depending on the OS).</p>
|
||||
<p>This might especially be useful if you want to invoke SWIG several times on separate modules, but compile the resulting code into a single shared library.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
<H2><a name="D_typemaps">23.3 Typemaps</a></H2>
|
||||
|
||||
|
||||
<H3><a name="D_typemap_name_comparison">23.3.1 C# <-> D name comparison</a></H3>
|
||||
|
||||
|
||||
<p>If you already know the SWIG C# module, you might find the following name comparison table useful:</p>
|
||||
|
||||
<div class="diagram"><pre>
|
||||
ctype <-> ctype
|
||||
imtype <-> imtype
|
||||
cstype <-> dtype
|
||||
csin <-> din
|
||||
csout <-> dout
|
||||
csdirectorin <-> ddirectorin
|
||||
csdirectorout <-> ddirectorout
|
||||
csinterfaces <-> dinterfaces
|
||||
csinterfaces_derived <-> dinterfaces_derived
|
||||
csbase <-> dbase
|
||||
csclassmodifiers <-> dclassmodifiers
|
||||
cscode <-> dcode
|
||||
csimports <-> dimports
|
||||
csbody <-> dbody
|
||||
csfinalize <-> ddestructor
|
||||
csdisposing <-> ddispose
|
||||
csdisposing_derived <-> ddispose_derived
|
||||
</pre></div>
|
||||
|
||||
|
||||
<H3><a name="D_ctype_imtype_dtype">23.3.2 ctype, imtype, dtype</a></H3>
|
||||
|
||||
|
||||
<p>Mapping of types between the C/C++ library, the C/C++ library wrapper exposing the C functions, the D wrapper module importing these functions and the D proxy code.</p>
|
||||
|
||||
<p>The <tt>ctype</tt> typemap is used to determine the types to use in the C wrapper functions. The types from the <tt>imtype</tt> typemap are used in the extern(C) declarations of these functions in the intermediary D module. The <tt>dtype</tt> typemap contains the D types used in the D proxy module/class.</p>
|
||||
|
||||
|
||||
<H3><a name="D_in_out_directorin_direcetorout">23.3.3 in, out, directorin, directorout</a></H3>
|
||||
|
||||
|
||||
<p>Used for converting between the types for C/C++ and D when generating the code for the wrapper functions (on the C++ side).</p>
|
||||
|
||||
<p>The code from the <tt>in</tt> typemap is used to convert arguments to the C wrapper function to the type used in the wrapped code (<tt>ctype</tt>->original C++ type), the <tt>out</tt> typemap is utilized to convert values from the wrapped code to wrapper function return types (original C++ type-><tt>ctype</tt>).</p>
|
||||
|
||||
<p>The <tt>directorin</tt> typemap is used to convert parameters to the type used in the D director callback function, its return value is processed by <tt>directorout</tt> (see below).</p>
|
||||
|
||||
|
||||
<H3><a name="D_din_dout_ddirectorin_ddirectorout">23.3.4 din, dout, ddirectorin, ddirectorout</a></H3>
|
||||
|
||||
|
||||
<p>Typemaps for code generation in D proxy and type wrapper classes.</p>
|
||||
|
||||
<p><a name="D_din"></a>The <tt>din</tt> typemap is used for converting function parameter types from the type used in the proxy module or class to the type used in the intermediary D module (the <a href="D.html#D_dinput">$dinput</a> macro is replaced). To inject further parameter processing code before or after the call to the intermediary layer, the <tt>pre</tt>, <tt>post</tt> and <tt>terminator</tt> attributes can be used (please refer to the <a href="CSharp.html#CSharp_date_marshalling">C# date marshalling example</a> for more information on these).</p>
|
||||
|
||||
<p><a name="D_dout"></a>The <tt>dout</tt> typemap is used for converting function return values from the return type used in the intermediary D module to the type returned by the proxy function. The <tt>$excode</tt> special variable in <tt>dout</tt> typemaps is replaced by the <tt>excode</tt> typemap attribute code if the method can throw any exceptions from unmanaged code, otherwise by nothing (the <a href="D.html#D_imcall"><tt>$imcall</tt> and <tt>$owner</tt></a> macros are replaced).</p>
|
||||
|
||||
<p><a name="D_ddirectorinout"></a>The code from the <tt>ddirectorin</tt> and <tt>ddirectorout</tt> typemaps is used for conversion in director callback functions. Arguments are converted to the type used in the proxy class method they are calling by using the code from <tt>ddirectorin</tt>, the proxy class method return value is converted to the type the C++ code expects via the <tt>ddirectorout</tt> typemap (the <a href="D.html#D_dpcall"><tt>$dcall</tt> and <tt>$winput</tt></a> macros are replaced).</p>
|
||||
|
||||
<p>The full chain of type conversions when a director callback is invoked looks like this:</p>
|
||||
|
||||
<div class="diagram"><pre>
|
||||
type CPPClass::method(type a)
|
||||
↑ ↓
|
||||
<directorout> <directorin>
|
||||
↑ ↓
|
||||
ctype methodCallback(ctype a) C++
|
||||
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
imtype methodCallback(imtype a) D
|
||||
↑ ↓
|
||||
<ddirectorout> <ddirectorin>
|
||||
↑ ↓
|
||||
dtype DClass.method(dtype a)</pre></div>
|
||||
|
||||
|
||||
<H3><a name="D_typecheck_typemaps">23.3.5 typecheck typemaps</a></H3>
|
||||
|
||||
|
||||
<p>Because, unlike many scripting languages supported by SWIG, D does not need any dynamic dispatch helper to access an overloaded function, the purpose of these is merely to issue a warning for overloaded C++ functions that cannot be overloaded in D (as more than one C++ type maps to a single D type).</p>
|
||||
|
||||
|
||||
<H3><a name="D_code_injection_typemaps">23.3.6 Code injection typemaps</a></H3>
|
||||
|
||||
|
||||
<p>These typemaps are used for generating the skeleton of proxy classes for C++ types.</p>
|
||||
|
||||
<p>By overriding <tt>dbase</tt>, <tt>dinterfaces</tt> or <tt>dinterfaces_derived</tt>, the inheritance chain of the generated proxy class for a type can be modified. <tt>dclassmodifiers</tt> allows you to add any custom modifiers around the class keyword.</p>
|
||||
|
||||
<p>Using <tt>dcode</tt> and <tt>dimports</tt>, you can specify additional D code which will be emitted into the class body respectively the imports section of the D module the class is written to.</p>
|
||||
|
||||
<p><a name="D_class_code_typemaps"></a><tt>dconstructor</tt>, <tt>ddestructor</tt>, <tt>ddispose</tt> and <tt>ddispose_derived</tt> are used to generate the class constructor, destructor and <tt>dispose()</tt> method, respectively. The auxiliary code for handling the pointer to the C++ object is stored in <tt>dbody</tt> and <tt>dbody_derived</tt>. You can override them for specific types.</p>
|
||||
|
||||
<p>
|
||||
Code can also be injected into the D proxy class using <tt>%proxycode</tt>.
|
||||
</p>
|
||||
|
||||
<H3><a name="D_special_variables">23.3.7 Special variable macros</a></H3>
|
||||
|
||||
|
||||
<p>The standard SWIG special variables are available for use within typemaps as described in the <a href="Typemaps.html#Typemaps">Typemaps documentation</a>, for example <tt>$1</tt>, <tt>$input</tt>, <tt>$result</tt> etc.</p>
|
||||
|
||||
<p>When generating D wrappers, a few additional macros are available:</p>
|
||||
<dl>
|
||||
<dt><tt>$dclassname</tt> (C#: <tt>$csclassname</tt>)</dt>
|
||||
<dd>
|
||||
<p>This special variable works similar to <a href="Typemaps.html#Typemaps_special_variables"><tt>$n_type</tt></a> in that it returns the name of a type - it expands to the D proxy class name of the type being wrapped. If the type does not have an associated proxy class, it expands to the type wrapper class name, for example, <tt>SWIGTYPE_p_p_SomeCppClass</tt> is generated when wrapping <tt>SomeCppClass **</tt>.</p>
|
||||
<p>There are two other variants available, <tt>$&dclassname</tt> and <tt>$*dclassname</tt>. The former adds a level of indirection, while the latter removes one. For instance, when wrapping <tt>Foo **</tt>, <tt>$*dclassname</tt> would be replaced by the proxy class name corresponding to <tt>Foo *</tt>.</p>
|
||||
</dd>
|
||||
|
||||
<dt><tt>$dclazzname</tt> (C#: <tt>$csclazzname</tt>)</dt>
|
||||
<dd>
|
||||
<p>This special variable expands the fully qualified C++ class into the package name, if used by the <a href="SWIGPlus.html#SWIGPlus_nspace"><tt>nspace</tt> feature</a>, and the proxy class name, mangled for use as a function name. For example, <tt>Namespace1::Namespace2::Klass</tt> is expanded into <tt>Namespace1_Namespace2_Klass_</tt>.</p>
|
||||
<p>This special variable might be useful for calling certain functions in the wrapper layer (e.g. upcast wrappers) which are mangled like this.</p>
|
||||
</dd>
|
||||
|
||||
<dt><tt>$null</tt></dt>
|
||||
<dd><p>In code inserted into the generated C/C++ wrapper functions, this variable is replaced by either <tt>0</tt> or nothing at all, depending on whether the function has a return value or not. It can be used to bail out early e.g. in case of errors (<tt>return $null;</tt>).</p></dd>
|
||||
|
||||
<dt><a name="D_dinput"></a><tt>$dinput</tt> (C#: <tt>$csinput</tt>)</dt>
|
||||
<dd>
|
||||
<p>This variable is used in <tt><a href="D.html#D_din">din</a></tt> typemaps and is replaced by the expression which is to be passed to C/C++.</p>
|
||||
<p>For example, this input</p>
|
||||
<div class="code"><pre>
|
||||
%typemap(din) SomeClass * "SomeClass.getCPointer($dinput)"
|
||||
|
||||
%inline %{
|
||||
class SomeClass {};
|
||||
void foo(SomeClass *arg);
|
||||
%}</pre></div>
|
||||
<p>leads to the following D proxy code being generated:</p>
|
||||
<div class="targetlang"><pre>
|
||||
void foo(SomeClass arg) {
|
||||
example_im.foo(SomeClass.getCPointer(arg));
|
||||
}</pre></div></dd>
|
||||
|
||||
<dt><a name="D_imcall"></a><tt>$imcall</tt> and <tt>$owner</tt> (C#: <tt>$imcall</tt>)</dt>
|
||||
<dd>
|
||||
<p>These variables are used in <tt><a href="D.html#D_dout">dout</a></tt> typemaps. <tt>$imcall</tt> contains the call to the intermediary module which provides the value to be used, and <tt>$owner</tt> signals if the caller is responsible for managing the object lifetime (that is, if the called method is a constructor or has been marked via <tt>%newobject</tt>).</p>
|
||||
<p>Consider the following example:</p>
|
||||
<div class="code"><pre>
|
||||
%typemap(dout) SomeClass * {
|
||||
return new SomeClass($imcall, $owner);
|
||||
}
|
||||
|
||||
%inline %{
|
||||
class SomeClass;
|
||||
SomeClass *foo();
|
||||
|
||||
%newobject bar();
|
||||
SomeClass *bar();
|
||||
%}
|
||||
</pre></div>
|
||||
<p>The code generated for <tt>foo()</tt> and <tt>bar()</tt> looks like this:</p>
|
||||
<div class="targetlang"><pre>
|
||||
SomeClass foo() {
|
||||
return new SomeClass(example_im.foo(), false);
|
||||
}
|
||||
|
||||
SomeClass bar() {
|
||||
return new SomeClass(example_im.bar(), true);
|
||||
}
|
||||
</pre></div>
|
||||
</dd>
|
||||
|
||||
<dt><tt>$dcall</tt> and <tt>$winput</tt> (C#: <tt>$cscall</tt>, <tt>$iminput</tt>)</dt>
|
||||
<dd><a name="D_dpcall"></a><p>These variables are used in the director-specific typemaps <a href="D.html#D_ddirectorinout"><tt>ddirectorin</tt></a> and <a href="D.html#D_ddirectorinout"><tt>ddirectorout</tt></a>. They are more or less the reverse of the <tt>$imcall</tt> and <tt>$dinput</tt> macros: <tt>$dcall</tt> contains the invocation of the D proxy method of which the return value is to be passed back to C++, <tt>$winput</tt> contains the parameter value from C++.</p></dd>
|
||||
|
||||
<dt><tt>$excode</tt></dt>
|
||||
<dd><p>This variable is used in <tt>dout</tt> and <tt>dconstructor</tt> typemaps and is filled with the contents of the <tt>excode</tt> typemap attribute if an exception could be thrown from the C++ side. See the <a href="CSharp.html#CSharp_exceptions">C# documentation</a> for details.</p></dd>
|
||||
|
||||
<dt><tt>$dbaseclass</tt></dt>
|
||||
<dd><p>Currently for internal use only, it contains the D name of the C++ base class (if any) inside proxy classes.</p></dd>
|
||||
|
||||
<dt><tt>$directorconnect</tt></dt>
|
||||
<dd>
|
||||
<p>This macro is only valid inside the <tt><a href="D.html#D_class_code_typemaps">dconstructor</a></tt> typemap and contains the value of the <tt>dconstructor</tt> typemap attribute if the currently wrapped class has directors enabled.</p>
|
||||
<p>This is how the default <tt>dconstructor</tt> typemap looks like (you usually do not want to specify a custom one):</p>
|
||||
<div class="code"><pre>
|
||||
%typemap(dconstructor, excode=SWIGEXCODE,
|
||||
directorconnect="\n swigDirectorConnect();") SWIGTYPE {
|
||||
this($imcall, true);$excode$directorconnect
|
||||
}
|
||||
</pre></div>
|
||||
</dd>
|
||||
|
||||
<dt><a name="D_importtype"></a><tt>$importtype(SomeDType)</tt></dt>
|
||||
<dd>
|
||||
<p>This macro is used in the <tt>dimports</tt> typemap if a dependency on another D type generated by SWIG is added by a custom typemap.</p>
|
||||
<p>Consider the following code snippet:</p>
|
||||
<div class="code"><pre>
|
||||
%typemap(dinterfaces) SomeClass "AnInterface, AnotherInterface";
|
||||
</pre></div>
|
||||
<p>This causes SWIG to add <tt>AnInterface</tt> and <tt>AnotherInterface</tt> to the base class list of <tt>SomeClass</tt>:</p>
|
||||
<div class="targetlang"><pre>
|
||||
class SomeClass : AnInterface, AnotherInterface {
|
||||
...
|
||||
}
|
||||
</pre></div>
|
||||
<p>For this to work, <tt>AnInterface</tt> and <tt>AnotherInterface</tt> have to be in scope. If SWIG is not in split proxy mode, this is already the case, but if it is, they have to be added to the import list via the <tt>dimports</tt> typemap. Additionally, the import statement depends on the package SWIG is configured to emit the modules to.</p>
|
||||
<p>The <tt>$importtype</tt> macro helps you to elegantly solve this problem:</p>
|
||||
<div class="code"><pre>
|
||||
%typemap(dimports) RemoteMpe %{
|
||||
$importtype(AnInterface)
|
||||
$importtype(AnotherInterface)
|
||||
%}
|
||||
</pre></div>
|
||||
<p>If SWIG is in split proxy mode, it expands to an <tt>import</tt> statement for the specified type, to nothing if not.</p>
|
||||
</dd>
|
||||
|
||||
<dt><tt>$module</tt></dt>
|
||||
<dd><p>Expands to the name of the main proxy D module.</p></dd>
|
||||
|
||||
<dt><tt>$imdmodule</tt></dt>
|
||||
<dd><p>Contains the fully qualified name of the intermediary D module.</p></dd>
|
||||
</dl>
|
||||
|
||||
|
||||
<H2><a name="D_features">23.4 D and %feature</a></H2>
|
||||
|
||||
|
||||
<p>The D module defines a number of directives which modify the <a href="Customization.html#Customization_features">SWIG features</a> set globally or for a specific declaration:</p>
|
||||
|
||||
|
||||
<dl>
|
||||
<dt><tt>%dmanifestconst</tt> and <tt>%dconstvalue(value)</tt></dt>
|
||||
<dd>
|
||||
<p>Out of the box, SWIG generates accessor methods for C <tt>#defines</tt> and C++ constants. The <tt>%dmanifestconst</tt> directive enables wrapping these constants as D manifest constants (<tt>const</tt> in D1, <tt>enum</tt> in D2).</p>
|
||||
<p>For this to work, the C/C++ code for the constant value must directly compile as D code, though. If this is not the case, you can manually override the expression written to the D proxy module using the <tt>%dconstvalue</tt> directive, passing the new value as parameter.</p>
|
||||
<p>For <tt>enum</tt>s, again <tt>%dconstvalue</tt> can be used to override the value of an enum item if the initializer should not compile in D.</p>
|
||||
</dd>
|
||||
|
||||
<dt><tt>%dmethodmodifiers</tt></dt>
|
||||
<dd>
|
||||
<p>This directive can be used to override the modifiers for a proxy function. For instance, you could make a <tt>public</tt> C++ member function <tt>private</tt> in D like this:</p>
|
||||
<div class="code"><pre>
|
||||
%dmethodmodifiers A::foo "private";
|
||||
|
||||
%inline %{
|
||||
struct A {
|
||||
void foo();
|
||||
};
|
||||
%}
|
||||
</pre></div>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
<H2><a name="D_pragmas">23.5 Pragmas</a></H2>
|
||||
|
||||
|
||||
<p>There are a few SWIG pragmas specific to the D module, which you can use to influence the D code SWIG generates:</p>
|
||||
|
||||
<dl>
|
||||
<dt><tt>%pragma(d) imdmodulecode</tt></dt>
|
||||
<dd><p>The passed text (D code) is copied verbatim to the intermediary D module. For example, it can be (and is, internally) used to emit additional private helper code for the use by proxy typemaps.</p></dd>
|
||||
|
||||
<dt><tt>%pragma(d) imdmoduleimports</tt></dt>
|
||||
<dd><p>Additional code to be emitted to the imports section of the intermediary D module (the <a href="D.html#D_importtype">$importtype</a> macro can be used here). You probably want to use this in conjunction with the <tt>imdmodulecode</tt> pragma.</p></dd>
|
||||
|
||||
<dt><tt>%pragma(d) proxydmodulecode</tt></dt>
|
||||
<dd><p>Just like <tt>proxydmodulecode</tt>, the argument is copied to the proxy D module (if SWIG is in <a href="D.html#D_splitproxy">split proxy mode</a> and/or the <tt>nspace</tt> feature is used, it is emitted to the main proxy D module only).</p></dd>
|
||||
|
||||
<dt><tt>%pragma(d) globalproxyimports</tt></dt>
|
||||
<dd>
|
||||
<p>The D module currently does not support specifying dependencies on external modules (e.g. from the standard library) for the D typemaps. To add the import statements to the proxy modules (resp. to <em>all</em> proxy modules if in split proxy mode), you can use the <tt>globalproxyimports</tt> directive.</p>
|
||||
<p>For example:</p>
|
||||
<div class="code"><pre>
|
||||
%typemap(din) char[] "($dinput ? tango.stdc.stringz.toStringz($dinput) : null)"
|
||||
%pragma(d) globalproxyimports = "static import tango.stdc.stringz;";
|
||||
</pre></div>
|
||||
</dd>
|
||||
|
||||
<dt><tt>%pragma(d) wrapperloadercode</tt></dt>
|
||||
<dd>
|
||||
<p>The D code for loading the wrapper library (it is copied to the intermediary D module). The <tt>$wrapperloaderbindcode</tt> variable is replaced by the list of commands for binding the functions from the wrapper library to the symbols in the intermediary D module.</p>
|
||||
<p>Each time this pragma is specified, the previous value is overwritten.</p>
|
||||
</dd>
|
||||
|
||||
<dt><tt>%pragma(d) wrapperloaderbindcommand</tt></dt>
|
||||
<dd>
|
||||
<p>The D command to use for binding the wrapper functions from the C/C++ library to the symbols in the intermediary D module. The <tt>$function</tt> variable contains the name of the D function in the wrap module, the <tt>$symbol</tt> variable is replaced by the name of the symbol in the library.</p>
|
||||
<p>Each time this pragma is specified, the previous value is overwritten.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
<H2><a name="D_exceptions">23.6 D Exceptions</a></H2>
|
||||
|
||||
|
||||
<p>Out of the box, C++ exceptions are fundamentally incompatible to their equivalent in the D world and cannot simply be propagated to a calling D method. There is, however, an easy way to solve this problem: Just catch the exception in the C/C++ wrapper layer, pass the contents to D, and make the wrapper code rethrow the exception in the D world.</p>
|
||||
|
||||
<p>The implementation details of this are a bit crude, but the SWIG D module automatically takes care of this, as long as it is able to detect that an exception could potentially be thrown (e.g. because the C++ method has a <tt>throw(...)</tt> exception specification).</p>
|
||||
|
||||
<p>As this feature is implemented in exactly the same way it is for C#, please see the <a href="CSharp.html#CSharp_exceptions">C# documentation</a> for a more detailed explanation.</p>
|
||||
|
||||
|
||||
<H2><a name="D_directors">23.7 D Directors</a></H2>
|
||||
|
||||
|
||||
<p>When the directors feature is activated, SWIG generates extra code on both the C++ and the D side to enable cross-language polymorphism. Essentially, this means that if you subclass a proxy class in D, C++ code can access any overridden virtual methods just as if you created a derived class in C++.</p>
|
||||
|
||||
<p>There is no D specific documentation yet, but the way the feature is implemented is very similar to how it is done in <a href="Java.html#Java_directors">Java</a> and <a href="CSharp.html#CSharp_directors">C#</a>.
|
||||
</p>
|
||||
|
||||
|
||||
<H2><a name="D_other_features">23.8 Other features</a></H2>
|
||||
|
||||
|
||||
<H3><a name="D_nspace">23.8.1 Extended namespace support (nspace)</a></H3>
|
||||
|
||||
|
||||
<p>By default, SWIG flattens all C++ namespaces into a single target language namespace, but as for Java and C#, the <a href="SWIGPlus.html#SWIGPlus_nspace"><tt>nspace</tt></a> feature is supported for D. If it is active, C++ namespaces are mapped to D packages/modules. Note, however, that like for the other languages, <em>free</em> variables and functions are not supported yet; currently, they are all allows written to the main proxy D module.</p>
|
||||
|
||||
|
||||
<H3><a name="D_native_pointer_support">23.8.2 Native pointer support</a></H3>
|
||||
|
||||
|
||||
<p>Contrary to many of the scripting languages supported by SWIG, D fully supports C-style pointers. The D module thus includes a custom mechanism to wrap C pointers directly as D pointers where applicable, that is, if the type that is pointed to is represented the same in C and D (on the bit-level), dubbed a <em>primitive type</em> below.</p>
|
||||
|
||||
<p>Central to this custom pointer handling scheme are two typemap attributes: the <tt>cprimitive</tt> attribute on the <tt>dtype</tt> typemap and the <tt>nativepointer</tt> attribute on all the typemaps which influence the D side of the code (<tt>dtype</tt>, <tt>din</tt>, <tt>dout</tt>, ...). When a D typemap is looked up, the following happens behind the scenes:</p>
|
||||
|
||||
<p>First, the matching typemap is determined by the usual typemap lookup rules. Then, it is checked if the result has the <tt>nativepointer</tt> attribute set. If it is present, it means that its value should replace the typemap value <em>if and only if</em> the actual type the typemap is looked up for is a primitive type, a pointer to a primitive type (through an arbitrary level of indirections), or a function pointer with only primitive types in its signature.</p>
|
||||
|
||||
<p>To determine if a type should be considered primitive, the <tt>cprimitive</tt> attribute on its <tt>dtype</tt> attribute is used. For example, the <tt>dtype</tt> typemap for <tt>float</tt> has <tt>cprimitive="1"</tt>, so the code from the <tt>nativepointer</tt> attribute is taken into account e.g. for <tt>float **</tt> or the function pointer <tt>float (*)(float *)</tt>.</p>
|
||||
|
||||
|
||||
<H3><a name="D_operator_overloading">23.8.3 Operator overloading</a></H3>
|
||||
|
||||
|
||||
<p>The D module comes with basic operator overloading support for both D1 and D2. There are, however, a few limitations arising from conceptual differences between C++ and D:</p>
|
||||
|
||||
<p>The first key difference is that C++ supports free functions as operators (along with argument-dependent lookup), while D requires operators to be member functions of the class they are operating on. SWIG can only automatically generate wrapping code for member function operators; if you want to use operators defined as free functions in D, you need to handle them manually.</p>
|
||||
|
||||
<p>Another set of differences between C++ and D concerns individual operators. For example, there are quite a few operators which are overloadable in C++, but not in D, for example <tt>&&</tt> and <tt>||</tt>, but also <tt>!</tt>, and prefix increment/decrement operators in <a href="http://www.digitalmars.com/d/1.0/operatoroverloading.html">D1</a> resp. their postfix pendants in <a href="http://www.digitalmars.com/d/2.0/operatoroverloading.html">D2</a>.</p>
|
||||
|
||||
<p>There are also some cases where the operators can be translated to D, but the differences in the implementation details are big enough that a rather involved scheme would be required for automatic wrapping them, which has not been implemented yet. This affects, for example, the array subscript operator, <tt>[]</tt>, in combination with assignments - while <tt>operator []</tt> in C++ simply returns a reference which is then written to, D resorts to a separate <tt>opIndexAssign</tt> method -, or implicit casting (which was introduced in D2 via <tt>alias this</tt>). Despite the lack of automatic support, manually handling these cases should be perfectly possible.</p>
|
||||
|
||||
|
||||
<H3><a name="D_test_suite">23.8.4 Running the test-suite</a></H3>
|
||||
|
||||
|
||||
<p>As with any other language, the SWIG test-suite can be built for D using the <tt>*-d-test-suite</tt> targets of the top-level Makefile. By default, D1 is targeted, to build it with D2, use the optional <tt>D_VERSION</tt> variable, e.g. <tt>make check-d-test-suite D_VERSION=2</tt>.</p>
|
||||
|
||||
<p>Note: If you want to use GDC on Linux or another platform which requires you to link <tt>libdl</tt> for dynamically loading the shared library, you might have to add <tt>-ldl</tt> manually to the <tt>d_compile</tt> target in <tt>Examples/Makefile</tt>, because GDC does not currently honor the <tt>pragma(lib, ...)</tt> statement.</p>
|
||||
|
||||
|
||||
<H2><a name="D_typemap_examples">23.9 D Typemap examples</a></H2>
|
||||
|
||||
|
||||
<p>There are no D-specific typemap examples yet. However, with the above <a href="D.html#D_typemap_name_comparison">name comparison table</a>, you should be able to get an idea what can be done by looking at the <a href="CSharp.html#CSharp_typemap_examples">corresponding C# section</a>.</p>
|
||||
|
||||
|
||||
|
||||
<H2><a name="D_planned_features">23.10 Work in progress and planned features</a></H2>
|
||||
|
||||
|
||||
<p>There are a couple of features which are not implemented yet, but would be very useful and might be added in the near future:</p>
|
||||
|
||||
<ul>
|
||||
<li><em>Static linking:</em> Currently, the C wrapper code is compiled into a dynamic library, out of which the symbol addresses are looked up at runtime by the D part. If statically linking the different languages into one binary was supported, a tool-chain capable of performing IPO at link time could inline the wrapping code, effectively reducing the overhead for simple calls to zero.</li>
|
||||
<li><em>C array handling:</em> Many data structures in some C/C++ libraries contain array containing of a pointer to the first element and the element count. Currently, one must manually writing wrapper code to be able to access these from D. It should be possible to add a set of SWIG macros to semi-automatically generate conversion code.</li>
|
||||
</ul>
|
||||
|
||||
<p>Some generated code might also be a bit rough around the edges, particularly in the following areas:</p>
|
||||
|
||||
<ul>
|
||||
<li><em>Memory management:</em> Although the currently generated wrapper code works fine with regard to the GC for the test-suite, there might be issues coming up in real-world multi-threaded usage.</li>
|
||||
<li><em>D2 support</em>: Originally, the module has been developed for the use with D1, D2/Phobos support has been added in later. The basic features should work equally well for both, but there <em>could</em> be issues concerning const-correctness etc.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,859 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and Guile</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
|
||||
<H1><a name="Guile">25 SWIG and Guile</a></H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#Guile_nn1">Supported Guile Versions</a>
|
||||
<li><a href="#Guile_nn2">Meaning of "Module"</a>
|
||||
<li><a href="#Guile_nn3">Old GH Guile API</a>
|
||||
<li><a href="#Guile_nn4">Linkage</a>
|
||||
<ul>
|
||||
<li><a href="#Guile_nn5">Simple Linkage</a>
|
||||
<li><a href="#Guile_nn6">Passive Linkage</a>
|
||||
<li><a href="#Guile_nn7">Native Guile Module Linkage</a>
|
||||
<li><a href="#Guile_nn8">Old Auto-Loading Guile Module Linkage</a>
|
||||
<li><a href="#Guile_nn9">Hobbit4D Linkage</a>
|
||||
</ul>
|
||||
<li><a href="#Guile_nn10">Underscore Folding</a>
|
||||
<li><a href="#Guile_nn11">Typemaps</a>
|
||||
<li><a href="#Guile_nn12">Representation of pointers as smobs</a>
|
||||
<ul>
|
||||
<li><a href="#Guile_nn14">Smobs</a>
|
||||
<li><a href="#Guile_nn15">Garbage Collection</a>
|
||||
</ul>
|
||||
<li><a href="#Guile_nn16">Native Guile pointers</a>
|
||||
<li><a href="#Guile_nn17">Exception Handling</a>
|
||||
<li><a href="#Guile_nn18">Procedure documentation</a>
|
||||
<li><a href="#Guile_nn19">Procedures with setters</a>
|
||||
<li><a href="#Guile_nn20">GOOPS Proxy Classes</a>
|
||||
<ul>
|
||||
<li><a href="#Guile_nn21">Naming Issues</a>
|
||||
<li><a href="#Guile_nn22">Linking</a>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
This section details guile-specific support in SWIG.
|
||||
|
||||
<H2><a name="Guile_nn1">25.1 Supported Guile Versions</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG works with Guile versions 1.8.x and 2.0.x. Support for version
|
||||
1.6.x has been dropped. The last version of SWIG that still works with
|
||||
Guile version 1.6.x is SWIG 2.0.9.
|
||||
|
||||
<p>
|
||||
Note that starting with guile 2.0, the guile sources can be compiled for
|
||||
improved performance. This is currently not tested with swig
|
||||
so your mileage may vary. To be safe set environment variable
|
||||
GUILE_AUTO_COMPILE to 0 when using swig generated guile code.
|
||||
|
||||
<H2><a name="Guile_nn2">25.2 Meaning of "Module"</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
There are three different concepts of "module" involved, defined
|
||||
separately for SWIG, Guile, and Libtool. To avoid horrible confusion,
|
||||
we explicitly prefix the context, e.g., "guile-module".
|
||||
|
||||
<H2><a name="Guile_nn3">25.3 Old GH Guile API</a></H2>
|
||||
|
||||
|
||||
<p>Guile 1.8 and older could be interfaced using two different api's, the SCM
|
||||
or the GH API. The GH interface to guile is deprecated. Read more about why in the
|
||||
<a href="http://www.gnu.org/software/guile/docs/docs-1.6/guile-ref/GH.html#GH">Guile manual</a>.
|
||||
|
||||
<p>Support for the guile GH wrapper code generation has been dropped from SWIG. The last
|
||||
version of SWIG that can still generate guile GH wrapper code is 2.0.9. Please
|
||||
use that version if you really need the GH wrapper code.
|
||||
|
||||
<H2><a name="Guile_nn4">25.4 Linkage</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
Guile support is complicated by a lack of user community cohesiveness,
|
||||
which manifests in multiple shared-library usage conventions. A set of
|
||||
policies implementing a usage convention is called a <b>linkage</b>.
|
||||
|
||||
<H3><a name="Guile_nn5">25.4.1 Simple Linkage</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
The default linkage is the simplest; nothing special is done. In this
|
||||
case the function <code>SWIG_init()</code> is exported. Simple linkage
|
||||
can be used in several ways:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><b>Embedded Guile, no modules.</b> You want to embed a Guile
|
||||
interpreter into your program; all bindings made by SWIG shall show up
|
||||
in the root module. Then call <code>SWIG_init()</code> in the
|
||||
<code>inner_main()</code> function. See the "simple" and "matrix" examples under
|
||||
<code>Examples/guile</code>.
|
||||
|
||||
<li><p><b>Dynamic module mix-in.</b> You want to create a Guile module
|
||||
using <code>define-module</code>, containing both Scheme code and
|
||||
bindings made by SWIG; you want to load the SWIG modules as shared
|
||||
libraries into Guile.</p>
|
||||
<div class="targetlang">
|
||||
<pre>
|
||||
(define-module (my module))
|
||||
(define my-so (dynamic-link "./libexample.so"))
|
||||
(dynamic-call "SWIG_init" my-so) ; make SWIG bindings
|
||||
;; Scheme definitions can go here
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Newer Guile versions provide a shorthand for <code>dynamic-link</code>
|
||||
and <code>dynamic-call</code>:
|
||||
</p>
|
||||
|
||||
<div class="targetlang">
|
||||
<pre>
|
||||
(load-extension "./libexample.so" "SWIG_init")
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
A more portable approach would be to drop the shared library extension:
|
||||
</p>
|
||||
|
||||
<div class="targetlang">
|
||||
<pre>
|
||||
(load-extension "./libexample" "SWIG_init")
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
You need to explicitly export those bindings made by SWIG that you
|
||||
want to import into other modules:
|
||||
</p>
|
||||
|
||||
<div class="targetlang">
|
||||
<pre>
|
||||
(export foo bar)
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
In this example, the procedures <code>foo</code> and <code>bar</code>
|
||||
would be exported. Alternatively, you can export all bindings with the
|
||||
following module-system hack:
|
||||
</p>
|
||||
|
||||
<div class="targetlang">
|
||||
<pre>
|
||||
(module-map (lambda (sym var)
|
||||
(module-export! (current-module) (list sym)))
|
||||
(current-module))
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>SWIG can also generate this Scheme stub (from
|
||||
<code>define-module</code> up to <code>export</code>)
|
||||
semi-automagically if you pass it the command-line argument
|
||||
<code>-scmstub</code>. The code will be exported in a file called
|
||||
<code><i>module</i>.scm</code> in the directory specified by <code>-outdir</code>
|
||||
or the current directory if <code>-outdir</code> is not specified.
|
||||
Since SWIG doesn't know how
|
||||
to load your extension module (with <code>dynamic-link</code> or
|
||||
<code>load-extension</code>), you need to supply this
|
||||
information by including a directive like this in the interface file:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%scheme %{ (load-extension "./libexample.so" "SWIG_init") %}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
(The <code>%scheme</code> directive allows to insert arbitrary Scheme
|
||||
code into the generated file <code><var>module.scm</var></code>; it is
|
||||
placed between the <code>define-module</code> form and the
|
||||
<code>export</code> form.)
|
||||
</p>
|
||||
</ul>
|
||||
|
||||
<p>If you want to include several SWIG modules, you would need to rename
|
||||
<code>SWIG_init</code> via a preprocessor define to avoid symbol
|
||||
clashes. For this case, however, passive linkage is available.
|
||||
|
||||
<H3><a name="Guile_nn6">25.4.2 Passive Linkage</a></H3>
|
||||
|
||||
|
||||
<p>Passive linkage is just like simple linkage, but it generates an
|
||||
initialization function whose name is derived from the module and
|
||||
package name (see below).
|
||||
|
||||
<p>You should use passive linkage rather than simple linkage when you
|
||||
are using multiple modules.
|
||||
|
||||
<H3><a name="Guile_nn7">25.4.3 Native Guile Module Linkage</a></H3>
|
||||
|
||||
|
||||
<p>SWIG can also generate wrapper code that does all the Guile module
|
||||
declarations on its own if you pass it the <code>-Linkage
|
||||
module</code> command-line option.
|
||||
|
||||
<p>The module name is set with the <code>-package</code> and
|
||||
<code>-module</code> command-line options. Suppose you want to define
|
||||
a module with name <code>(my lib foo)</code>; then you would have to
|
||||
pass the options <code>-package <var>my</var>/<var>lib</var> -module
|
||||
<var>foo</var></code>. Note that the last part of the name can also be set
|
||||
via the SWIG directive <code>%module</code>.
|
||||
|
||||
<p>You can use this linkage in several ways:
|
||||
|
||||
<ul>
|
||||
<li><b>Embedded Guile with SWIG modules.</b> You want to embed a Guile
|
||||
interpreter into your program; the SWIG bindings shall be put into
|
||||
different modules. Simply call the function
|
||||
<code>scm_init_<var>my</var>_<var>modules</var>_<var>foo</var>_module</code>
|
||||
in the <code>inner_main()</code> function.
|
||||
|
||||
<li><b>Dynamic Guile modules.</b> You want to load the SWIG modules as
|
||||
shared libraries into Guile; all bindings are automatically put in
|
||||
newly created Guile modules.
|
||||
<div class="targetlang">
|
||||
<pre>
|
||||
(define my-so (dynamic-link "./libfoo"))
|
||||
;; create new module and put bindings there:
|
||||
(dynamic-call "scm_init_my_modules_foo_module" my-so)
|
||||
</pre>
|
||||
</div>
|
||||
Newer Guile versions have a shorthand procedure for this:
|
||||
<div class="targetlang">
|
||||
<pre>
|
||||
(load-extension "./libfoo.so" "scm_init_my_modules_foo_module")
|
||||
</pre>
|
||||
</div>
|
||||
</ul>
|
||||
|
||||
<H3><a name="Guile_nn8">25.4.4 Old Auto-Loading Guile Module Linkage</a></H3>
|
||||
|
||||
|
||||
<p>Guile used to support an autoloading facility for object-code
|
||||
modules. This support has been marked deprecated in version 1.4.1 and
|
||||
is going to disappear sooner or later. SWIG still supports building
|
||||
auto-loading modules if you pass it the <code>-Linkage ltdlmod</code>
|
||||
command-line option.
|
||||
|
||||
<p>Auto-loading worked like this: Suppose a module with name <code>(my
|
||||
lib foo)</code> is required and not loaded yet. Guile will then search
|
||||
all directories in its search path
|
||||
for a Scheme file <code>my/modules/foo.scm</code> or a shared library
|
||||
<code><var>my</var>/<var>modules</var>/lib<var>foo</var>.so</code> (or
|
||||
<code><var>my</var>/<var>modules</var>/lib<var>foo</var>.la</code>;
|
||||
see the GNU libtool documentation). If a
|
||||
shared library is found that contains the symbol
|
||||
<code>scm_init_<var>my</var>_<var>modules</var>_<var>foo</var>_module</code>,
|
||||
the library is loaded, and the function at that symbol is called with
|
||||
no arguments in order to initialize the module.
|
||||
|
||||
<p>When invoked with the <code>-Linkage ltdlmod</code> command-line
|
||||
option, SWIG generates an exported module initialization function with
|
||||
an appropriate name.
|
||||
|
||||
|
||||
<H3><a name="Guile_nn9">25.4.5 Hobbit4D Linkage</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
The only other linkage supported at this time creates shared object
|
||||
libraries suitable for use by hobbit's <code>(hobbit4d link)</code>
|
||||
guile module. This is called the "hobbit" linkage, and requires also
|
||||
using the "-package" command line option to set the part of the module
|
||||
name before the last symbol. For example, both command lines:
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
swig -guile -package my/lib foo.i
|
||||
swig -guile -package my/lib -module foo foo.i
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
would create module <code>(my lib foo)</code> (assuming in the first
|
||||
case foo.i declares the module to be "foo"). The installed files are
|
||||
my/lib/libfoo.so.X.Y.Z and friends. This scheme is still very
|
||||
experimental; the (hobbit4d link) conventions are not well understood.
|
||||
</p>
|
||||
|
||||
<H2><a name="Guile_nn10">25.5 Underscore Folding</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
Underscores are converted to dashes in identifiers. Guile support may
|
||||
grow an option to inhibit this folding in the future, but no one has
|
||||
complained so far.
|
||||
|
||||
<p>You can use the SWIG directives <code>%name</code> and
|
||||
<code>%rename</code> to specify the Guile name of the wrapped
|
||||
functions and variables (see CHANGES).
|
||||
|
||||
<H2><a name="Guile_nn11">25.6 Typemaps</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
The Guile module handles all types via typemaps. This
|
||||
information is read from <code>Lib/guile/typemaps.i</code>.
|
||||
|
||||
Some non-standard typemap substitutions are supported:
|
||||
<ul>
|
||||
<li><code>$descriptor</code> expands to a type descriptor for use with
|
||||
the <code>SWIG_NewPointerObj()</code> and
|
||||
<code>SWIG_ConvertPtr</code> functions.
|
||||
<li>For pointer types, <code>$*descriptor</code> expands to a
|
||||
descriptor for the direct base type (i.e., one pointer is stripped),
|
||||
whereas <code>$basedescriptor</code> expands to a
|
||||
descriptor for the base type (i.e., all pointers are stripped).
|
||||
</ul>
|
||||
|
||||
<p>A function returning <code>void</code> (more precisely, a function
|
||||
whose <code>out</code> typemap returns <code>SCM_UNSPECIFIED</code>) is
|
||||
treated as returning no values. In <code>argout</code> typemaps, one
|
||||
can use the macro <code>GUILE_APPEND_RESULT</code> in order to append
|
||||
a value to the list of function return values.
|
||||
|
||||
<p>Multiple values can be passed up to Scheme in one of three ways:
|
||||
<ul>
|
||||
<li><p><em>Multiple values as lists.</em>
|
||||
By default, if more than one value is to
|
||||
be returned, a list of the values is created and returned; to switch
|
||||
back to this behavior, use</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%values_as_list;</pre>
|
||||
</div>
|
||||
|
||||
<li><p><em>Multiple values as vectors.</em>
|
||||
By issuing
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%values_as_vector;</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
vectors instead of lists will be used.
|
||||
<li><p><em>Multiple values for multiple-value continuations.</em>
|
||||
<strong>This is the most elegant way.</strong> By issuing
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%multiple_values;</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
multiple values are passed to the multiple-value
|
||||
continuation, as created by <code>call-with-values</code> or the
|
||||
convenience macro <code>receive</code>. The latter is available if you
|
||||
issue <code>(use-modules (srfi srfi-8))</code>. Assuming that your
|
||||
<code>divide</code> function
|
||||
wants to return two values, a quotient and a remainder, you can write:
|
||||
</p>
|
||||
|
||||
<div class="targetlang">
|
||||
<pre>
|
||||
(receive (quotient remainder)
|
||||
(divide 35 17)
|
||||
<var>body</var>...)
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
In <code><var>body</var></code>, the first result of
|
||||
<code>divide</code> will be bound to the variable
|
||||
<code>quotient</code>, and the second result to <code>remainder</code>.
|
||||
</p>
|
||||
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
See also the "multivalue" example.
|
||||
</p>
|
||||
|
||||
<p>Constants are exported as a function that returns the value. The
|
||||
%feature("constasvar") can be applied to any constant, immutable variable, or enum.
|
||||
Instead of exporting the constant as a function that must be called, the
|
||||
constant will appear as a scheme variable. See
|
||||
<a href="Customization.html#Customization_features">Features and the %feature directive</a>
|
||||
for info on how to apply the %feature.</p>
|
||||
|
||||
<H2><a name="Guile_nn12">25.7 Representation of pointers as smobs</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
For pointer types, SWIG uses Guile smobs. SWIG smobs print
|
||||
like this: <code>#<swig struct xyzzy * 0x1234affe></code> Two of
|
||||
them are <code>equal?</code> if and only if they have the same type
|
||||
and value.
|
||||
|
||||
<p>
|
||||
To construct a Scheme object from a C pointer, the wrapper code calls
|
||||
the function <code>SWIG_NewPointerObj()</code>, passing a pointer to a
|
||||
struct representing the pointer type. The type index to store in the
|
||||
upper half of the CAR is read from this struct.
|
||||
To get the pointer represented by a smob, the wrapper code calls the
|
||||
function <code>SWIG_ConvertPtr()</code>, passing a pointer to a struct
|
||||
representing the expected pointer type. See also
|
||||
<a href="Typemaps.html#Typemaps_runtime_type_checker">The run-time type checker</a>.
|
||||
If the Scheme object passed was not a SWIG smob representing a compatible
|
||||
pointer, a <code>wrong-type-arg</code> exception is raised.
|
||||
|
||||
<H3><a name="Guile_nn14">25.7.1 Smobs</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
In earlier versions of SWIG, C pointers were represented as Scheme
|
||||
strings containing a hexadecimal rendering of the pointer value and a
|
||||
mangled type name. As Guile allows registering user types, so-called
|
||||
"smobs" (small objects), a much cleaner representation has been
|
||||
implemented now. The details will be discussed in the following.
|
||||
</p>
|
||||
|
||||
<p>The whole type system, when it is first initialized, creates two smobs named "swig" and "collected_swig".
|
||||
The swig smob is used for non-garbage collected smobs, while the collected_swig smob is used as described
|
||||
below. Each smob has the same format, which is a double cell created by SCM_NEWSMOB2()
|
||||
The first word of data is the pointer to the object and the second word of data is the swig_type_info *
|
||||
structure describing this type. If a generated GOOPS module has been loaded, smobs will be wrapped by
|
||||
the corresponding GOOPS class.</p>
|
||||
|
||||
|
||||
<H3><a name="Guile_nn15">25.7.2 Garbage Collection</a></H3>
|
||||
|
||||
|
||||
<p>Garbage collection is a feature of Guile since version 1.6. As SWIG now requires Guile > 1.8,
|
||||
it is automatically included.
|
||||
Garbage collection works like this. Every swig_type_info structure stores in its clientdata field a pointer
|
||||
to the destructor for this type. The destructor is the generated wrapper around the delete function.
|
||||
So swig still exports a wrapper for the destructor, it just does not call scm_c_define_gsubr() for
|
||||
the wrapped delete function. So the only way to delete an object is from the garbage collector, since the
|
||||
delete function is not available to scripts. How swig determines if a type should be garbage collected
|
||||
is exactly like described in <a href="Customization.html#Customization_ownership">
|
||||
Object ownership and %newobject</a> in the SWIG manual. All typemaps use an $owner var, and
|
||||
the guile module replaces $owner with 0 or 1 depending on feature:new.</p>
|
||||
|
||||
<H2><a name="Guile_nn16">25.8 Native Guile pointers</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
In addition to SWIG smob pointers, <a href="https://www.gnu.org/software/guile/manual/html_node/Foreign-Pointers.html">Guile's native pointer type</a> are accepted as arguments to wrapped SWIG functions. This can be useful for passing <a href="https://www.gnu.org/software/guile/manual/html_node/Void-Pointers-and-Byte-Access.html#">pointers to bytevector data</a> to wrapped functions.
|
||||
</p>
|
||||
|
||||
<H2><a name="Guile_nn17">25.9 Exception Handling</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG code calls <code>scm_error</code> on exception, using the following
|
||||
mapping:
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
MAP(SWIG_MemoryError, "swig-memory-error");
|
||||
MAP(SWIG_IOError, "swig-io-error");
|
||||
MAP(SWIG_RuntimeError, "swig-runtime-error");
|
||||
MAP(SWIG_IndexError, "swig-index-error");
|
||||
MAP(SWIG_TypeError, "swig-type-error");
|
||||
MAP(SWIG_DivisionByZero, "swig-division-by-zero");
|
||||
MAP(SWIG_OverflowError, "swig-overflow-error");
|
||||
MAP(SWIG_SyntaxError, "swig-syntax-error");
|
||||
MAP(SWIG_ValueError, "swig-value-error");
|
||||
MAP(SWIG_SystemError, "swig-system-error");
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The default when not specified here is to use "swig-error".
|
||||
See Lib/exception.i for details.
|
||||
|
||||
<H2><a name="Guile_nn18">25.10 Procedure documentation</a></H2>
|
||||
|
||||
|
||||
<p>If invoked with the command-line option <code>-procdoc
|
||||
<var>file</var></code>, SWIG creates documentation strings for the
|
||||
generated wrapper functions, describing the procedure signature and
|
||||
return value, and writes them to <var>file</var>.
|
||||
|
||||
<p>SWIG can generate documentation strings in three formats, which are
|
||||
selected via the command-line option <code>-procdocformat
|
||||
<var>format</var></code>:
|
||||
<ul>
|
||||
<li><code>guile-1.4</code> (default): Generates a format suitable for Guile 1.4.
|
||||
<li><code>plain</code>: Generates a format suitable for Guile 1.4.1 and
|
||||
later.
|
||||
<li><code>texinfo</code>: Generates texinfo source, which must be run
|
||||
through texinfo in order to get a format suitable for Guile 1.4.1 and
|
||||
later.
|
||||
</ul>
|
||||
|
||||
<p>You need to register the generated documentation file with Guile
|
||||
like this:
|
||||
|
||||
<div class="targetlang">
|
||||
<pre>
|
||||
(use-modules (ice-9 documentation))
|
||||
(set! documentation-files
|
||||
(cons "<var>file</var>" documentation-files))
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>Documentation strings can be configured using the Guile-specific
|
||||
typemap argument <code>doc</code>. See <code>Lib/guile/typemaps.i</code> for
|
||||
details.
|
||||
|
||||
<H2><a name="Guile_nn19">25.11 Procedures with setters</a></H2>
|
||||
|
||||
|
||||
<p>For global variables, SWIG creates a single wrapper procedure
|
||||
<code>(<var>variable</var> :optional value)</code>, which is used for
|
||||
both getting and setting the value. For struct members, SWIG creates
|
||||
two wrapper procedures <code>(<var>struct</var>-<var>member</var>-get
|
||||
pointer)</code> and <code>(<var>struct-member</var>-set pointer value)</code>.
|
||||
|
||||
<p>If invoked with the command-line option <code>-emit-setters</code>
|
||||
(<em>recommended</em>),
|
||||
SWIG will additionally create procedures with setters. For global
|
||||
variables, the procedure-with-setter <code><var>variable</var></code>
|
||||
is created, so you can use <code>(<var>variable</var>)</code> to get
|
||||
the value and <code>(set! (<var>variable</var>)
|
||||
<var>value</var>)</code> to set it. For struct members, the
|
||||
procedure-with-setter <code><var>struct</var>-<var>member</var></code>
|
||||
is created, so you can use <code>(<var>struct</var>-<var>member</var>
|
||||
<var>pointer</var>)</code> to get the value and <code>(set!
|
||||
(<var>struct</var>-<var>member</var> <var>pointer</var>)
|
||||
<var>value</var>)</code> to set it.
|
||||
|
||||
<p>If invoked with the command-line option <code>-only-setters</code>,
|
||||
SWIG will <em>only</em> create procedures with setters, i.e., for
|
||||
struct members, the procedures <code>(<var>struct</var>-<var>member</var>-get
|
||||
pointer)</code> and <code>(<var>struct-member</var>-set pointer
|
||||
value)</code> are <em>not</em> generated.
|
||||
|
||||
<H2><a name="Guile_nn20">25.12 GOOPS Proxy Classes</a></H2>
|
||||
|
||||
|
||||
<p>SWIG can also generate classes and generic functions for use with
|
||||
Guile's Object-Oriented Programming System (GOOPS). GOOPS is a
|
||||
sophisticated object system in the spirit of the Common Lisp Object
|
||||
System (CLOS).
|
||||
|
||||
<p>To enable GOOPS support, pass the <code>-proxy</code> argument to
|
||||
swig. This will export the GOOPS wrapper definitions into the
|
||||
<code><i>module</i>.scm</code> file in the directory specified by -outdir or the
|
||||
current directory. GOOPS support requires either passive or module linkage.</p>
|
||||
|
||||
<p>The generated file will contain definitions of GOOPS classes mimicking the C++ class hierarchy.
|
||||
<p>Enabling GOOPS support implies <code>-emit-setters</code>.
|
||||
|
||||
<p>If <code>-emit-slot-accessors</code> is also passed as an argument,
|
||||
then the generated file will contain accessor methods for all the
|
||||
slots in the classes and for global variables. The input class</p>
|
||||
<div class="code"><pre>
|
||||
class Foo {
|
||||
public:
|
||||
Foo(int i) : a(i) {}
|
||||
int a;
|
||||
int getMultBy(int i) { return a * i; }
|
||||
Foo getFooMultBy(int i) { return Foo(a * i); }
|
||||
};
|
||||
Foo getFooPlus(int i) { return Foo(a + i); }
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
will produce (if <code>-emit-slot-accessors</code> is not passed as a parameter)
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
(define-class <Foo> (<swig>)
|
||||
(a #:allocation #:swig-virtual
|
||||
#:slot-ref primitive:Foo-a-get
|
||||
#:slot-set! primitive:Foo-a-set)
|
||||
#:metaclass <swig-metaclass>
|
||||
#:new-function primitive:new-Foo
|
||||
)
|
||||
(define-method (getMultBy (swig_smob <Foo>) i)
|
||||
(primitive:Foo-getMultBy (slot-ref swig_smob 'smob) i))
|
||||
(define-method (getFooMultBy (swig_smob <Foo>) i)
|
||||
(make <Foo> #:init-smob (primitive:Foo-getFooMultBy (slot-ref swig_smob 'smob) i)))
|
||||
|
||||
(define-method (getFooPlus i)
|
||||
(make <Foo> #:init-smob (primitive:getFooPlus i)))
|
||||
|
||||
(export <Foo> getMultBy getFooMultBy getFooPlus )
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
and will produce (if <code>-emit-slot-accessors</code> is passed as a parameter)
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
(define-class <Foo> (<swig>)
|
||||
(a #:allocation #:swig-virtual
|
||||
#:slot-ref primitive:Foo-a-get
|
||||
#:slot-set! primitive:Foo-a-set
|
||||
<b>#:accessor a</b>)
|
||||
#:metaclass <swig-metaclass>
|
||||
#:new-function primitive:new-Foo
|
||||
)
|
||||
(define-method (getMultBy (swig_smob <Foo>) i)
|
||||
(primitive:Foo-getMultBy (slot-ref swig_smob 'smob) i))
|
||||
(define-method (getFooMultBy (swig_smob <Foo>) i)
|
||||
(make <Foo> #:init-smob (primitive:Foo-getFooMultBy (slot-ref swig_smob 'smob) i)))
|
||||
|
||||
(define-method (getFooPlus i)
|
||||
(make <Foo> #:init-smob (primitive:getFooPlus i)))
|
||||
|
||||
(export <Foo> <b>a</b> getMultBy getFooMultBy getFooPlus )
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
which can then be used by this code
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
;; not using getters and setters
|
||||
(define foo (make <Foo> #:args '(45)))
|
||||
(slot-ref foo 'a)
|
||||
(slot-set! foo 'a 3)
|
||||
(getMultBy foo 4)
|
||||
(define foo2 (getFooMultBy foo 7))
|
||||
(slot-ref foo 'a)
|
||||
(slot-ref (getFooPlus foo 4) 'a)
|
||||
|
||||
;; using getters and setters
|
||||
(define foo (make <Foo> #:args '(45)))
|
||||
(a foo)
|
||||
(set! (a foo) 5)
|
||||
(getMultBy foo 4)
|
||||
(a (getFooMultBy foo 7))
|
||||
</pre></div>
|
||||
|
||||
<p>Notice that constructor arguments are passed as a list after the <code>#:args</code> keyword. Hopefully in
|
||||
the future the following will be valid <code>(make <Foo> #:a 5 #:b 4)</code></p>
|
||||
|
||||
<p>Also note that the order the declarations occur in the .i file make a difference. For example,
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%module test
|
||||
|
||||
%{ #include "foo.h" %}
|
||||
|
||||
%inline %{
|
||||
int someFunc(Foo &a) {
|
||||
...
|
||||
}
|
||||
%}
|
||||
|
||||
%include "foo.h"
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
This is a valid SWIG file it will work as you think it will for primitive support, but the generated
|
||||
GOOPS file will be broken. Since the <code>someFunc</code> definition is parsed by SWIG before all the
|
||||
declarations in foo.h, the generated GOOPS file will contain the definition of <code>someFunc()</code>
|
||||
before the definition of <Foo>. The generated GOOPS file would look like
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
;;...
|
||||
|
||||
(define-method (someFunc (swig_smob <Foo>))
|
||||
(primitive:someFunc (slot-ref swig_smob 'smob)))
|
||||
|
||||
;;...
|
||||
|
||||
(define-class <Foo> (<swig>)
|
||||
;;...
|
||||
)
|
||||
|
||||
;;...
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Notice that <Foo> is used before it is defined. The fix is to just put the
|
||||
<code>%import "foo.h"</code> before the <code>%inline</code> block.
|
||||
</p>
|
||||
|
||||
<H3><a name="Guile_nn21">25.12.1 Naming Issues</a></H3>
|
||||
|
||||
|
||||
<p>As you can see in the example above, there are potential naming conflicts. The default exported
|
||||
accessor for the <code>Foo::a</code> variable is named <code>a</code>. The name of the wrapper global
|
||||
function is <code>getFooPlus</code>.
|
||||
If the <code>-useclassprefix</code> option is passed to swig, the name of all accessors and member
|
||||
functions will be prepended with the class name. So the accessor will be called <code>Foo-a</code> and
|
||||
the member functions will be called <code>Foo-getMultBy</code>. Also, if the
|
||||
<code>-goopsprefix goops:</code> argument is passed to swig, every identifier will be prefixed by
|
||||
<code>goops:</code></p>
|
||||
|
||||
<p>Two guile-modules are created by SWIG. The first module contains the primitive definitions
|
||||
of all the wrapped functions and variables, and is located either in the _wrap.cxx file (with <code>-Linkage
|
||||
module</code>) or in the scmstub file (if <code>-Linkage passive -scmstub</code>). The name of this
|
||||
guile-module is the swig-module name (given on the command line with the -module argument or with the
|
||||
%module directive) concatenated with the string "-primitive". For
|
||||
example, if <code>%module Test</code> is set in the swig interface file, the name of the guile-module in
|
||||
the scmstub or <code>-Linkage module</code> will be <code>Test-primitive</code>. Also, the scmstub
|
||||
file will be named <code>Test-primitive.scm</code>.
|
||||
The string "primitive" can be changed by the <code>-primsuffix</code> swig
|
||||
argument. So the same interface, with the <code>-primsuffix base</code> will produce a module called
|
||||
<code>Test-base</code>.
|
||||
The second generated guile-module contains all the GOOPS class definitions and is located in
|
||||
a file named <i>module</i>.scm in the directory specified with -outdir or the current directory.
|
||||
The name of this guile-module is the name of the
|
||||
swig-module (given on the command line or with the <code>%module</code> directive).
|
||||
In the previous example, the GOOPS definitions will be in a file named Test.scm.</p>
|
||||
|
||||
<p>Because of the naming conflicts, you can't in general use both the <code>-primitive</code> and the GOOPS
|
||||
guile-modules at the same time. To do this, you need to rename the exported symbols from one or both
|
||||
guile-modules. For example,</p>
|
||||
<div class="targetlang"><pre>
|
||||
(use-modules ((Test-primitive) #:renamer (symbol-prefix-proc 'primitive:)))
|
||||
(use-modules ((Test) #:renamer (symbol-prefix-proc 'goops:)))
|
||||
</pre></div>
|
||||
|
||||
<H3><a name="Guile_nn22">25.12.2 Linking</a></H3>
|
||||
|
||||
|
||||
<p>The guile-modules generated above all need to be linked together. GOOPS support requires
|
||||
either passive or module linkage. The exported GOOPS guile-module will be the name of the swig-module
|
||||
and should be located in a file called <i>Module</i>.scm. This should be installed on the autoload
|
||||
path for guile, so that <code>(use-modules (<i>Package Module</i>))</code> will load everything needed.
|
||||
Thus, the top of the GOOPS guile-module will contain code to load everything needed by the interface
|
||||
(the shared library, the scmstub module, etc.).
|
||||
The <code>%goops</code> directive inserts arbitrary code into the generated GOOPS guile-module, and
|
||||
should be used to load the dependent libraries.</p>
|
||||
|
||||
<p>This breaks up into three cases</p>
|
||||
<ul>
|
||||
<li><b>Passive Linkage without -scmstub</b>: Note that this linkage style has the potential for naming
|
||||
conflicts, since the primitive exported function and variable names are not wrapped in a guile-module
|
||||
and might conflict with names from the GOOPS guile-module (see above). Pass the -goopsprefix
|
||||
argument to solve this problem. If the <code>-exportprimitive</code> option is passed to SWIG the
|
||||
<code>(export ...)</code> code that would be exported into the scmstub file is exported at the bottom
|
||||
of the generated GOOPS guile-module.
|
||||
The <code>%goops</code> directive should contain code to load the shared library.
|
||||
|
||||
<div class="code"><pre>
|
||||
%goops %{ (load-extension "./libfoo.so" "scm_init_my_modules_foo_module") %}
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Produces the following code at the top of the generated GOOPS guile-module
|
||||
(with the <code>-package my/modules -module foo</code> command line arguments)
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
(define-module (my modules foo))
|
||||
|
||||
;; %goops directive goes here
|
||||
(load-extension "./libfoo.so" "scm_init_my_modules_foo_module")
|
||||
|
||||
(use-modules (oop goops) (Swig common))
|
||||
</pre></div>
|
||||
</li>
|
||||
|
||||
<li><p><b>Passive Linkage with -scmstub</b>: Here, the name of the scmstub file should be
|
||||
<code>Module-primitive.scm</code> (with <i>primitive</i> replaced with whatever is given with the <code>-primsuffix</code>
|
||||
argument. The code to load the shared library should be located in the <code>%scheme</code> directive,
|
||||
which will then be added to the scmstub file.
|
||||
SWIG will automatically generate the line <code>(use-modules (<i>Package</i> <i>Module-primitive</i>))</code>
|
||||
into the GOOPS guile-module. So if <i>Module-primitive.scm</i> is on the autoload path for guile, the
|
||||
<code>%goops</code> directive can be empty. Otherwise, the <code>%goops</code> directive should contain
|
||||
whatever code is needed to load the <i>Module-primitive.scm</i> file into guile.</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
%scheme %{ (load-extension "./libfoo.so" "scm_init_my_modules_foo_module") %}
|
||||
// only include the following definition if (my modules foo) cannot
|
||||
// be loaded automatically
|
||||
%goops %{
|
||||
(primitive-load "/path/to/foo-primitive.scm")
|
||||
(primitive-load "/path/to/Swig/common.scm")
|
||||
%}
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Produces the following code at the top of the generated GOOPS guile-module
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
(define-module (my modules foo))
|
||||
|
||||
;; %goops directive goes here (if any)
|
||||
(primitive-load "/path/to/foo-primitive.scm")
|
||||
(primitive-load "/path/to/Swig/common.scm")
|
||||
|
||||
(use-modules (oop goops) (Swig common))
|
||||
(use-modules ((my modules foo-primitive) :renamer (symbol-prefix-proc
|
||||
'primitive:)))
|
||||
|
||||
</pre></div>
|
||||
</li>
|
||||
|
||||
<li><p><b>Module Linkage</b>: This is very similar to passive linkage with a scmstub file.
|
||||
SWIG will also automatically generate the line <code>(use-modules
|
||||
(<i>Package</i> <i>Module-primitive</i>))</code> into the GOOPS guile-module. Again the <code>%goops</code>
|
||||
directive should contain whatever code is needed to get that module loaded into guile.</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%goops %{ (load-extension "./libfoo.so" "scm_init_my_modules_foo_module") %}
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Produces the following code at the top of the generated GOOPS guile-module
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
(define-module (my modules foo))
|
||||
|
||||
;; %goops directive goes here (if any)
|
||||
(load-extension "./libfoo.so" "scm_init_my_modules_foo_module")
|
||||
|
||||
(use-modules (oop goops) (Swig common))
|
||||
(use-modules ((my modules foo-primitive) :renamer (symbol-prefix-proc
|
||||
'primitive:)))
|
||||
|
||||
</pre></div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p><b>(Swig common)</b>: The generated GOOPS guile-module also imports definitions from the
|
||||
(Swig common) guile-module.
|
||||
This module is included with SWIG and should be installed by SWIG into the autoload path for
|
||||
guile (based on the configure script and whatever arguments are passed). If it is not, then the
|
||||
<code>%goops</code> directive also needs to contain code to load the <code>common.scm</code> file
|
||||
into guile. Also note that if you are trying to install the generated wrappers on a computer without
|
||||
SWIG installed, you will need to include the common.swg file along with the install.</p>
|
||||
|
||||
<p><b>Multiple Modules</b>: Type dependencies between modules is supported. For example, if
|
||||
<code>mod1</code> includes definitions of some classes, and <code>mod2</code> includes some classes
|
||||
derived from classes in <code>mod1</code>, the generated GOOPS file for <code>mod2</code> will declare
|
||||
the correct superclasses. The only problem is that since <code>mod2</code> uses symbols from
|
||||
<code>mod1</code>, the <code>mod2</code> GOOPS file must include a <code>(use-modules (mod2))</code>.
|
||||
Currently, SWIG does not automatically export this line; it must be included in the <code>%goops</code>
|
||||
directive of <code>mod2</code>. Maybe in the future SWIG can detect dependencies and export this line.
|
||||
(how do other language modules handle this problem?)</p>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,549 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Introduction</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<H1><a name="Introduction">2 Introduction</a></H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#Introduction_nn2">What is SWIG?</a>
|
||||
<li><a href="#Introduction_nn3">Why use SWIG?</a>
|
||||
<li><a href="#Introduction_target_languages">Target languages</a>
|
||||
<ul>
|
||||
<li><a href="#Introduction_supported_status">Supported status</a>
|
||||
<li><a href="#Introduction_experimental_status">Experimental status</a>
|
||||
</ul>
|
||||
<li><a href="#Introduction_nn4">A SWIG example</a>
|
||||
<ul>
|
||||
<li><a href="#Introduction_nn5">SWIG interface file</a>
|
||||
<li><a href="#Introduction_nn6">The swig command</a>
|
||||
<li><a href="#Introduction_nn7">Building a Perl5 module</a>
|
||||
<li><a href="#Introduction_nn8">Building a Python module</a>
|
||||
<li><a href="#Introduction_nn9">Shortcuts</a>
|
||||
</ul>
|
||||
<li><a href="#Introduction_nn10">Supported C/C++ language features</a>
|
||||
<li><a href="#Introduction_nn11">Non-intrusive interface building</a>
|
||||
<li><a href="#Introduction_build_system">Incorporating SWIG into a build system</a>
|
||||
<li><a href="#Introduction_nn12">Hands off code generation</a>
|
||||
<li><a href="#Introduction_nn13">SWIG and freedom</a>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<H2><a name="Introduction_nn2">2.1 What is SWIG?</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG is a software development tool that simplifies the task of
|
||||
interfacing different languages to C and C++ programs. In a
|
||||
nutshell, SWIG is a compiler that takes C/C++ declarations and creates
|
||||
the wrappers needed to access those declarations from other languages
|
||||
including Perl, Python, Tcl, Ruby, Guile, and Java. SWIG normally
|
||||
requires no modifications to existing code and can often be used to
|
||||
build a usable interface in only a few minutes. Possible applications
|
||||
of SWIG include:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Building interpreted interfaces to existing C programs.
|
||||
<li>Rapid prototyping and application development.
|
||||
<li>Interactive debugging.
|
||||
<li>Reengineering or refactoring of legacy software into scripting language components.
|
||||
<li>Making a graphical user interface (using Tk for example).
|
||||
<li>Testing of C libraries and programs (using scripts).
|
||||
<li>Building high performance C modules for scripting languages.
|
||||
<li>Making C programming more enjoyable (or tolerable depending on your point of view).
|
||||
<li>Impressing your friends.
|
||||
<li>Obtaining vast sums of research funding (although obviously not applicable to the author).
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
SWIG was originally designed to make it extremely easy for scientists
|
||||
and engineers to build extensible scientific software without having to get a
|
||||
degree in software engineering. Because of this, the use of
|
||||
SWIG tends to be somewhat informal and ad-hoc (e.g., SWIG does not
|
||||
require users to provide formal interface specifications as you would find in
|
||||
a dedicated IDL compiler). Although
|
||||
this style of development isn't appropriate for every
|
||||
project, it is particularly well suited to software development in the
|
||||
small; especially the research and development work that is commonly found
|
||||
in scientific and engineering projects. However, nowadays SWIG is known to be used in many
|
||||
large open source and commercial projects.
|
||||
|
||||
<H2><a name="Introduction_nn3">2.2 Why use SWIG?</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
As stated in the previous section, the primary purpose of SWIG is to simplify
|
||||
the task of integrating C/C++ with other programming languages. However, why would
|
||||
anyone want to do that? To answer that question, it is useful to list a few strengths
|
||||
of C/C++ programming:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Excellent support for writing programming libraries.
|
||||
<li>High performance (number crunching, data processing, graphics, etc.).
|
||||
<li>Systems programming and systems integration.
|
||||
<li>Large user community and software base.
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Next, let's list a few problems with C/C++ programming
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Writing a user interface is rather painful (i.e., consider programming with MFC, X11, GTK, or any number
|
||||
of other libraries).
|
||||
<li>Testing is time consuming (the compile/debug cycle).
|
||||
<li>Not easy to reconfigure or customize without recompilation.
|
||||
<li>Modularization can be tricky.
|
||||
<li>Security concerns (buffer overflows for instance).
|
||||
</ul>
|
||||
<p>
|
||||
To address these limitations, many programmers have arrived at the
|
||||
conclusion that it is much easier to use different programming
|
||||
languages for different tasks. For instance, writing a graphical user
|
||||
interface may be significantly easier in a scripting language like
|
||||
Python or Tcl (consider the reasons why millions of programmers have used languages like
|
||||
Visual Basic if you need more proof). An interactive interpreter might also serve as a
|
||||
useful debugging and testing tool. Other languages like Java might
|
||||
greatly simplify the task of writing distributed computing software.
|
||||
The key point is that different programming languages offer different
|
||||
strengths and weaknesses. Moreover, it is extremely unlikely that any
|
||||
programming is ever going to be perfect. Therefore, by combining
|
||||
languages together, you can utilize the best features of each language
|
||||
and greatly simplify certain aspects of software development.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
From the standpoint of C/C++, a lot of people use SWIG because they want to break
|
||||
out of the traditional monolithic C programming model which usually results
|
||||
in programs that resemble this:
|
||||
|
||||
<ul>
|
||||
<li>A collection of functions and variables that do something useful.
|
||||
<li>A <tt>main()</tt> program that starts everything.
|
||||
<li>A horrible collection of hacks that form some kind of user interface (but
|
||||
which no-one really wants to touch).
|
||||
</ul>
|
||||
<p>
|
||||
Instead of going down that route, incorporating C/C++ into a higher level language
|
||||
often results in a more modular design, less code, better flexibility, and increased
|
||||
programmer productivity.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
SWIG tries to make the problem of C/C++ integration as painless as possible.
|
||||
This allows you to focus on the underlying C
|
||||
program and using the high-level language interface, but not
|
||||
the tedious and complex chore of making the two languages talk to each
|
||||
other. At the same time, SWIG recognizes that all applications are different. Therefore,
|
||||
it provides a wide variety of customization features that let you change almost
|
||||
every aspect of the language bindings. This is the main reason why SWIG has such a large
|
||||
user manual ;-).
|
||||
|
||||
<H2><a name="Introduction_target_languages">2.3 Target languages</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG in essence is a tool to generate code for making C/C++ code available to various other programming languages.
|
||||
These higher level programming languages are the target languages for the SWIG code generator and C or C++ are the input languages.
|
||||
A single target language must be specified when SWIG is run.
|
||||
This results in generating code for C/C++ and the specified target language to interface with each other.
|
||||
SWIG can be invoked multiple times, but with a different target language specified on each invocation.
|
||||
This ability to interface C/C++ to many different target languages is one of SWIG's core strengths and features.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
SWIG is very broadly composed of two components.
|
||||
A core component creates a parse tree from the input ISO C/C++ and SWIG directives (extensions to the C/C++ standards).
|
||||
The parse tree is then passed to a second component, one of the target language modules for generating code specific to a higher level language.
|
||||
SWIG supports many different target languages.
|
||||
These target languages are given a status of either Supported or Experimental.
|
||||
This status is provided to indicate the level of maturity to expect when using a particular target language as not all target languages are fully developed.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The second part of the SWIG documentation contains a chapter for each target level language.
|
||||
Each chapter will state the status (Supported or Experimental) for that language.
|
||||
</p>
|
||||
|
||||
<H3><a name="Introduction_supported_status">2.3.1 Supported status</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
A target language is given the 'Supported' status when
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>It is in a mature, well functioning state.</li>
|
||||
<li>It has its own comprehensive chapter in the documentation.</li>
|
||||
<li>It passes all of the main SWIG test-suite and has a range of working examples.</li>
|
||||
<li>It supports the vast majority of SWIG features.</li>
|
||||
<li>It provides strong backwards compatibility between releases.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
The above is a short summary and further details are outlined in the <a href="Extending.html#Extending_supported_status">Supported status</a> section in the Extending chapter.
|
||||
The good news is that all the well-known and most popular languages have this status.
|
||||
</p>
|
||||
|
||||
<H3><a name="Introduction_experimental_status">2.3.2 Experimental status</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
A target language is given the 'Experimental' status when
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>It is of sub-standard quality, failing to meet the above 'Supported' status.</li>
|
||||
<li>It is somewhere between the mid to mature stage of development.</li>
|
||||
<li>It does not guarantee any backwards compatibility between releases.</li>
|
||||
<li>It is in need of help to finish development.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Anyone using an experimental target language is strongly urged to assist with development of the target language module if they wish to use it.
|
||||
</p>
|
||||
<p>
|
||||
SWIG displays a warning when an experimental target language is used in order to set expectations and emphasize the experimental status of the target language.
|
||||
The usual <a href="Warnings.html#Warnings_suppression">warning suppression</a> techniques can be used if required.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The above is a short summary and further details are outlined in the <a href="Extending.html#Extending_experimental_status">Experimental status</a> section in the Extending chapter.
|
||||
</p>
|
||||
|
||||
<H2><a name="Introduction_nn4">2.4 A SWIG example</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
The best way to illustrate SWIG is with a simple example. Consider the
|
||||
following C code:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
/* File : example.c */
|
||||
|
||||
double My_variable = 3.0;
|
||||
|
||||
/* Compute factorial of n */
|
||||
int fact(int n) {
|
||||
if (n <= 1)
|
||||
return 1;
|
||||
else
|
||||
return n*fact(n-1);
|
||||
}
|
||||
|
||||
/* Compute n mod m */
|
||||
int my_mod(int n, int m) {
|
||||
return(n % m);
|
||||
}
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Suppose that you wanted to access these functions and the global
|
||||
variable <tt>My_variable</tt> from Tcl. You start by making a SWIG
|
||||
interface file as shown below (by convention, these files carry a .i
|
||||
suffix) :
|
||||
|
||||
<H3><a name="Introduction_nn5">2.4.1 SWIG interface file</a></H3>
|
||||
|
||||
|
||||
<div class="code"><pre>
|
||||
/* File : example.i */
|
||||
%module example
|
||||
%{
|
||||
/* Put headers and other declarations here */
|
||||
extern double My_variable;
|
||||
extern int fact(int);
|
||||
extern int my_mod(int n, int m);
|
||||
%}
|
||||
|
||||
extern double My_variable;
|
||||
extern int fact(int);
|
||||
extern int my_mod(int n, int m);
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
The interface file contains ISO C function prototypes and variable
|
||||
declarations. The <tt>%module</tt> directive defines the name of the
|
||||
module that will be created by SWIG. The <tt>%{ %}</tt> block
|
||||
provides a location for inserting additional code, such as C header
|
||||
files or additional C declarations, into the generated C wrapper code.
|
||||
|
||||
<H3><a name="Introduction_nn6">2.4.2 The swig command</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG is invoked using the <tt>swig</tt> command. We can use this to
|
||||
build a Tcl module (under Linux) as follows :
|
||||
</p>
|
||||
|
||||
<div class="shell"><pre>
|
||||
unix > <b>swig -tcl example.i</b>
|
||||
unix > <b>gcc -c -fpic example.c example_wrap.c -I/usr/local/include</b>
|
||||
unix > <b>gcc -shared example.o example_wrap.o -o example.so</b>
|
||||
unix > <b>tclsh</b>
|
||||
% <b>load ./example.so</b>
|
||||
% <b>fact 4</b>
|
||||
24
|
||||
% <b>my_mod 23 7</b>
|
||||
2
|
||||
% <b>expr $My_variable + 4.5</b>
|
||||
7.5
|
||||
%
|
||||
</pre></div>
|
||||
<p>
|
||||
The <tt>swig</tt> command produced a new file called
|
||||
<tt>example_wrap.c</tt> that should be compiled along with the
|
||||
<tt>example.c</tt> file. Most operating systems and scripting
|
||||
languages now support dynamic loading of modules. In our example, our
|
||||
Tcl module has been compiled into a shared library that can be loaded
|
||||
into Tcl. When loaded, Tcl can now access the functions
|
||||
and variables declared in the SWIG interface. A look at the file
|
||||
<tt>example_wrap.c</tt> reveals a hideous mess. However, you
|
||||
almost never need to worry about it.
|
||||
|
||||
<H3><a name="Introduction_nn7">2.4.3 Building a Perl5 module</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Now, let's turn these functions into a Perl5 module. Without making
|
||||
any changes type the following (shown for Solaris):
|
||||
</p>
|
||||
|
||||
<div class="shell"><pre>
|
||||
unix > <b>swig -perl5 example.i</b>
|
||||
unix > <b>gcc -c example.c example_wrap.c \
|
||||
-I/usr/local/lib/perl5/sun4-solaris/5.003/CORE</b>
|
||||
unix > <b>ld -G example.o example_wrap.o -o example.so</b> # This is for Solaris
|
||||
unix > <b>perl5.003
|
||||
use example;
|
||||
print example::fact(4), "\n";
|
||||
print example::my_mod(23, 7), "\n";
|
||||
print $example::My_variable + 4.5, "\n";
|
||||
<ctrl-d></b>
|
||||
24
|
||||
2
|
||||
7.5
|
||||
unix >
|
||||
</pre></div>
|
||||
|
||||
|
||||
<H3><a name="Introduction_nn8">2.4.4 Building a Python module</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Finally, let's build a module for Python (shown for Irix).
|
||||
</p>
|
||||
|
||||
<div class="shell"><pre>
|
||||
unix > <b>swig -python example.i</b>
|
||||
unix > <b>gcc -c -fpic example.c example_wrap.c -I/usr/local/include/python2.0</b>
|
||||
unix > <b>gcc -shared example.o example_wrap.o -o _example.so</b>
|
||||
unix > <b>python</b>
|
||||
Python 2.0 (#6, Feb 21 2001, 13:29:45)
|
||||
[GCC egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)] on linux2
|
||||
Type "copyright", "credits" or "license" for more information.
|
||||
>>> <b>import example</b>
|
||||
>>> <b>example.fact(4)</b>
|
||||
24
|
||||
>>> <b>example.my_mod(23, 7)</b>
|
||||
2
|
||||
>>> <b>example.cvar.My_variable + 4.5</b>
|
||||
7.5
|
||||
</pre></div>
|
||||
|
||||
<H3><a name="Introduction_nn9">2.4.5 Shortcuts</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
To the truly lazy programmer, one may wonder why we needed the extra
|
||||
interface file at all. As it turns out, you can often do without
|
||||
it. For example, you could also build a Perl5 module by just running
|
||||
SWIG on the C header file and specifying a module name as follows
|
||||
</p>
|
||||
|
||||
<div class="shell"><pre>
|
||||
unix > <b>swig -perl5 -module example example.h</b>
|
||||
unix > <b>gcc -c example.c example_wrap.c \
|
||||
-I/usr/local/lib/perl5/sun4-solaris/5.003/CORE</b>
|
||||
unix > <b>ld -G example.o example_wrap.o -o example.so</b>
|
||||
unix > <b>perl5.003
|
||||
use example;
|
||||
print example::fact(4), "\n";
|
||||
print example::my_mod(23, 7), "\n";
|
||||
print $example::My_variable + 4.5, "\n";
|
||||
<ctrl-d></b>
|
||||
24
|
||||
2
|
||||
7.5
|
||||
</pre></div>
|
||||
|
||||
<H2><a name="Introduction_nn10">2.5 Supported C/C++ language features</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
A primary goal of the SWIG project is to make the language binding
|
||||
process extremely easy. Although a few simple examples have been shown,
|
||||
SWIG is quite capable in supporting most of C++. Some of the
|
||||
major features include:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Full C99 preprocessing.
|
||||
<li>All ISO C and C++ datatypes.
|
||||
<li>Functions, variables, and constants.
|
||||
<li>Classes.
|
||||
<li>Single and multiple inheritance.
|
||||
<li>Overloaded functions and methods.
|
||||
<li>Overloaded operators.
|
||||
<li>C++ templates (including member templates, specialization, and partial specialization).
|
||||
<li>Namespaces.
|
||||
<li>Variable length arguments.
|
||||
<li>C++ smart pointers.
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Most of C++11 is also supported. Details are in the <a href="CPlusPlus11.html#CPlusPlus11">C++11</a> chapter.
|
||||
C++14 support is covered in the <a href="CPlusPlus14.html#CPlusPlus14">C++14</a> chapter.
|
||||
C++17 support is covered in the <a href="CPlusPlus17.html#CPlusPlus17">C++17</a> chapter.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It is important to stress that SWIG is not a simplistic C++ lexing
|
||||
tool like several apparently similar wrapper generation tools. SWIG
|
||||
not only parses C++, it implements the full C++ type system and it is
|
||||
able to understand C++ semantics. SWIG generates its wrappers with
|
||||
full knowledge of this information. As a result, you will find SWIG
|
||||
to be just as capable of dealing with nasty corner cases as it is in
|
||||
wrapping simple C++ code. In fact, SWIG is able to handle C++ code that
|
||||
stresses the very limits of many C++ compilers.
|
||||
|
||||
|
||||
<H2><a name="Introduction_nn11">2.6 Non-intrusive interface building</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
When used as intended, SWIG requires minimal (if any) modification to
|
||||
existing C or C++ code. This makes SWIG extremely easy to use with existing
|
||||
packages and promotes software reuse and modularity. By making
|
||||
the C/C++ code independent of the high level interface, you can change the
|
||||
interface and reuse the code in other applications. It is also
|
||||
possible to support different types of interfaces depending on the application.
|
||||
</p>
|
||||
|
||||
<H2><a name="Introduction_build_system">2.7 Incorporating SWIG into a build system</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG is a command line tool and as such can be incorporated into any build system that supports invoking external tools/compilers.
|
||||
SWIG is most commonly invoked from within a Makefile, but is also known to be invoked from popular IDEs such as
|
||||
Microsoft Visual Studio.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you are using the GNU Autotools
|
||||
(<a href="http://www.gnu.org/software/autoconf/">Autoconf</a>/
|
||||
<a href="http://www.gnu.org/software/automake/">Automake</a>/
|
||||
<a href="http://www.gnu.org/software/libtool/">Libtool</a>)
|
||||
to configure SWIG use in your project, the SWIG Autoconf macros can be used.
|
||||
The primary macro is <tt>ax_pkg_swig</tt>, see
|
||||
<a href="http://www.gnu.org/software/autoconf-archive/ax_pkg_swig.html#ax_pkg_swig">http://www.gnu.org/software/autoconf-archive/ax_pkg_swig.html#ax_pkg_swig</a>.
|
||||
The <tt>ax_python_devel</tt> macro is also helpful for generating Python extensions. See the
|
||||
<a href="http://www.gnu.org/software/autoconf-archive/">Autoconf Archive</a>
|
||||
for further information on this and other Autoconf macros.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
There is growing support for SWIG in some build tools, for example <a href="https://cmake.org">CMake</a>
|
||||
is a cross-platform, open-source build manager with built in support for SWIG. CMake can detect the SWIG executable
|
||||
and many of the target language libraries for linking against.
|
||||
CMake knows how to build shared libraries and loadable modules on many different operating systems.
|
||||
This allows easy cross platform SWIG development. It can also generate the custom commands necessary for
|
||||
driving SWIG from IDEs and makefiles. All of this can be done from a single cross platform input file.
|
||||
The following example is a CMake input file for creating a Python wrapper for the SWIG interface file, example.i:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
|
||||
# This is a CMake example for Python
|
||||
|
||||
FIND_PACKAGE(SWIG REQUIRED)
|
||||
INCLUDE(${SWIG_USE_FILE})
|
||||
|
||||
FIND_PACKAGE(PythonLibs)
|
||||
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH})
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
SET(CMAKE_SWIG_FLAGS "")
|
||||
|
||||
SET_SOURCE_FILES_PROPERTIES(example.i PROPERTIES CPLUSPLUS ON)
|
||||
SET_SOURCE_FILES_PROPERTIES(example.i PROPERTIES SWIG_FLAGS "-includeall")
|
||||
SWIG_ADD_MODULE(example python example.i example.cxx)
|
||||
SWIG_LINK_LIBRARIES(example ${PYTHON_LIBRARIES})
|
||||
|
||||
</pre></div>
|
||||
<p>
|
||||
The above example will generate native build files such as makefiles, nmake files and Visual Studio projects
|
||||
which will invoke SWIG and compile the generated C++ files into _example.so (UNIX) or _example.pyd (Windows).
|
||||
For other target languages on Windows a dll, instead of a .pyd file, is usually generated.
|
||||
</p>
|
||||
|
||||
<H2><a name="Introduction_nn12">2.8 Hands off code generation</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG is designed to produce working code that needs no
|
||||
hand-modification (in fact, if you look at the output, you probably
|
||||
won't want to modify it). You should think of your target language interface being
|
||||
defined entirely by the input to SWIG, not the resulting output
|
||||
file. While this approach may limit flexibility for hard-core hackers,
|
||||
it allows others to forget about the low-level implementation
|
||||
details.
|
||||
</p>
|
||||
|
||||
<H2><a name="Introduction_nn13">2.9 SWIG and freedom</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
No, this isn't a special section on the sorry state of world politics.
|
||||
However, it may be useful to know that SWIG was written with a
|
||||
certain "philosophy" about programming---namely that programmers are
|
||||
smart and that tools should just stay out of their way. Because of
|
||||
that, you will find that SWIG is extremely permissive in what it lets
|
||||
you get away with. In fact, you can use SWIG to go well beyond
|
||||
"shooting yourself in the foot" if dangerous programming is your goal.
|
||||
On the other hand, this kind of freedom may be exactly what is needed
|
||||
to work with complicated and unusual C/C++ applications.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Ironically, the freedom that SWIG provides is countered by an
|
||||
extremely conservative approach to code generation. At its core, SWIG
|
||||
tries to distill even the most advanced C++ code down to a small
|
||||
well-defined set of interface building techniques based on ISO C
|
||||
programming. Because of this, you will find that SWIG interfaces can
|
||||
be easily compiled by virtually every C/C++ compiler and that they can
|
||||
be used on any platform. Again, this is an important part of staying out
|
||||
of the programmer's way----the last thing any developer wants to do is
|
||||
to spend their time debugging the output of a tool that relies on
|
||||
non-portable or unreliable programming features.
|
||||
Dependencies are often a source of incompatibilities and problems and so
|
||||
additional third party libraries are not used in the generated code.
|
||||
SWIG will also generally avoid generating code that introduces a dependency
|
||||
on the C++ Standard Template Library (STL).
|
||||
SWIG will generate code that depends on the C libraries though.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,998 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<title></title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<H1><a name="Javascript">27 SWIG and Javascript</a></H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#Javascript_overview">Overview</a>
|
||||
<li><a href="#Javascript_preliminaries">Preliminaries</a>
|
||||
<ul>
|
||||
<li><a href="#Javascript_running_swig">Running SWIG</a>
|
||||
<li><a href="#Javascript_running_tests_examples">Running Tests and Examples</a>
|
||||
<li><a href="#Javascript_known_issues">Known Issues</a>
|
||||
</ul>
|
||||
<li><a href="#Javascript_integration">Integration</a>
|
||||
<ul>
|
||||
<li><a href="#Javascript_node_extensions">Creating node.js Extensions</a>
|
||||
<ul>
|
||||
<li><a href="#Javascript_troubleshooting">Troubleshooting</a>
|
||||
</ul>
|
||||
<li><a href="#Javascript_embedded_webkit">Embedded Webkit</a>
|
||||
<ul>
|
||||
<li><a href="#Javascript_osx">Mac OS X</a>
|
||||
<li><a href="#Javascript_gtk">GTK</a>
|
||||
</ul>
|
||||
<li><a href="#Javascript_applications_webkit">Creating Applications with node-webkit</a>
|
||||
</ul>
|
||||
<li><a href="#Javascript_examples">Examples</a>
|
||||
<ul>
|
||||
<li><a href="#Javascript_simple_example">Simple</a>
|
||||
<li><a href="#Javascript_class_example">Class</a>
|
||||
</ul>
|
||||
<li><a href="#Javascript_implementation">Implementation</a>
|
||||
<ul>
|
||||
<li><a href="#Javascript_source_code">Source Code</a>
|
||||
<li><a href="#Javascript_code_templates">Code Templates</a>
|
||||
<li><a href="#Javascript_emitter">Emitter</a>
|
||||
<li><a href="#Javascript_emitter_states">Emitter states</a>
|
||||
<li><a href="#Javascript_jsc_exceptions">Handling Exceptions in JavascriptCore</a>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<p>This chapter describes SWIG's support of Javascript. It does not cover SWIG basics, but only information that is specific to this module.</p>
|
||||
|
||||
<H2><a name="Javascript_overview">27.1 Overview</a></H2>
|
||||
|
||||
|
||||
<p>Javascript is a prototype-based scripting language that is dynamic, weakly typed and has first-class functions. Its arguably the most popular language for web development.
|
||||
Javascript has gone beyond being a browser-based scripting language and with <a href="https://nodejs.org">node.js</a>, it is also used as a backend development language.</p>
|
||||
<p>Native Javascript extensions can be used for applications that embed a web-browser view or that embed a Javascript engine (such as <em>node.js</em>). Extending a general purpose web-browser is not possible as this would be a severe security issue.</p>
|
||||
<p>SWIG Javascript currently supports <strong>JavascriptCore</strong>, the Javascript engine used by <code>Safari/Webkit</code>, and <a href="https://v8.dev/"><strong>v8</strong></a>, which is used by <code>Chromium</code> and <code>node.js</code>.</p>
|
||||
<p><a href="https://webkit.org/">WebKit</a> is a modern browser implementation available as open-source which can be embedded into an application.
|
||||
With <a href="https://github.com/rogerwang/node-webkit">node-webkit</a> there is a platform which uses Google's <code>Chromium</code> as Web-Browser widget and <code>node.js</code> for javascript extensions.
|
||||
</p>
|
||||
|
||||
<H2><a name="Javascript_preliminaries">27.2 Preliminaries</a></H2>
|
||||
|
||||
|
||||
<H3><a name="Javascript_running_swig">27.2.1 Running SWIG</a></H3>
|
||||
|
||||
|
||||
<p>Suppose that you defined a SWIG module such as the following:</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
%module example
|
||||
%{
|
||||
#include "example.h"
|
||||
%}
|
||||
int gcd(int x, int y);
|
||||
extern double Foo;</pre>
|
||||
</div>
|
||||
<p>To build a Javascript module, run SWIG using the <code>-javascript</code> option and a desired target engine <code>-jsc</code>, <code>-v8</code>, or <code>-node</code>. The generator for <code>node</code> is essentially delegating to the <code>v8</code> generator and adds some necessary preprocessor definitions.</p>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ swig -javascript -jsc example.i</pre>
|
||||
</div>
|
||||
<p>If building a C++ extension, add the -c++ option:</p>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ swig -c++ -javascript -jsc example.i</pre>
|
||||
</div>
|
||||
<p>The V8 code that SWIG generates should work with most versions from 3.11.10 up to 3.29.14 and later.</p>
|
||||
<p>The API headers for V8 >= 4.3.0 define constants which SWIG can use to
|
||||
determine the V8 version it is compiling for. For versions < 4.3.0, you
|
||||
need to specify the V8 version when running SWIG. This is specified as a hex
|
||||
constant, but the constant is read as pairs of decimal digits, so for V8
|
||||
3.25.30 use constant 0x032530. This scheme can't represent components > 99,
|
||||
but this constant is only useful for V8 < 4.3.0, and no V8 versions from
|
||||
that era had a component > 99. For example:</p>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ swig -c++ -javascript -v8 -DV8_VERSION=0x032530 example.i</pre>
|
||||
</div>
|
||||
<p>If you're targeting V8 >= 4.3.0, you would just run swig like so:</p>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ swig -c++ -javascript -v8 example.i</pre>
|
||||
</div>
|
||||
<p>This creates a C/C++ source file <code>example_wrap.c</code> or <code>example_wrap.cxx</code>. The generated C source file contains the low-level wrappers that need to be compiled and linked with the rest of your C/C++ application to create an extension module.</p>
|
||||
<p>The name of the wrapper file is derived from the name of the input file. For example, if the input file is <code>example.i</code>, the name of the wrapper file is <code>example_wrap.c</code>. To change this, you can use the -o option. The wrapped module will export one function which must be called to register the module with the Javascript interpreter. For example, if your module is named <code>example</code> the corresponding initializer for JavascriptCore would be</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
bool example_initialize(JSGlobalContextRef context, JSObjectRef *exports)</pre>
|
||||
</div>
|
||||
<p>and for v8:</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
void example_initialize(v8::Handle<v8::Object> exports)</pre>
|
||||
</div>
|
||||
<p>
|
||||
<b>Note</b>: be aware that <code>v8</code> has a C++ API, and thus, the generated modules must be compiled as C++.
|
||||
</p>
|
||||
|
||||
<H3><a name="Javascript_running_tests_examples">27.2.2 Running Tests and Examples</a></H3>
|
||||
|
||||
|
||||
<p>The configuration for tests and examples currently supports Linux and Mac only and not MinGW (Windows) yet.</p>
|
||||
<p>The default interpreter is <code>node.js</code> as it is available on all platforms and convenient to use.</p>
|
||||
<p>Running the examples with JavascriptCore requires <code>libjavascriptcoregtk-1.0</code> to be installed, e.g., under Ubuntu with</p>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ sudo apt-get install libjavascriptcoregtk-1.0-dev</pre>
|
||||
</div>
|
||||
<p>Running with <code>V8</code> requires <code>libv8</code>:</p>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ sudo apt-get install libv8-dev</pre>
|
||||
</div>
|
||||
<p>Examples can be run using</p>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ make check-javascript-examples ENGINE=jsc</pre>
|
||||
</div>
|
||||
<p><code>ENGINE</code> can be <code>node</code>, <code>jsc</code>, or <code>v8</code>.</p>
|
||||
<p>The test-suite can be run using</p>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ make check-javascript-test-suite ENGINE=jsc</pre>
|
||||
</div>
|
||||
<p>You can specify a specific <code>V8</code> version for running the examples and tests</p>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ make check-javascript-examples V8_VERSION=0x032530 ENGINE=v8</pre>
|
||||
</div>
|
||||
|
||||
<H3><a name="Javascript_known_issues">27.2.3 Known Issues</a></H3>
|
||||
|
||||
|
||||
<p>At the moment, the Javascript generators pass all tests syntactically, i.e., the generated source code compiles. However, there are still remaining runtime issues.</p>
|
||||
|
||||
<ul>
|
||||
<li><p>Default optional arguments do not work for all targeted interpreters</p></li>
|
||||
<li><p>Multiple output arguments do not work for JSC</p></li>
|
||||
<li><p>C89 incompatibility: the JSC generator might still generate C89 violating code</p></li>
|
||||
<li><p><code>long long</code> is not supported</p></li>
|
||||
<li><p>Javascript callbacks are not supported</p></li>
|
||||
<li><p><code>instanceOf</code> does not work under JSC</p></li>
|
||||
</ul>
|
||||
|
||||
<p>The primary development environment has been Linux (Ubuntu 12.04). Windows and Mac OS X have been tested sporadically. Therefore, the generators might have more issues on those platforms. Please report back any problem you observe to help us improving this module quickly.</p>
|
||||
|
||||
<H2><a name="Javascript_integration">27.3 Integration</a></H2>
|
||||
|
||||
|
||||
<p>This chapter gives a short introduction how to use a native Javascript extension: as a <code>node.js</code> module, and as an extension for an embedded Webkit.</p>
|
||||
|
||||
<H3><a name="Javascript_node_extensions">27.3.1 Creating node.js Extensions</a></H3>
|
||||
|
||||
|
||||
<p>To install <code>node.js</code> you can download an installer from their <a href="https://launchpad.net/~chris-lea/+archive/node.js">web-site</a> for Mac OS X and Windows. For Linux you can either build the source yourself and run <code>sudo checkinstall</code> or keep to the (probably stone-age) packaged version. For Ubuntu there is a <a href="https://launchpad.net/~chris-lea/+archive/ubuntu/node.js/">PPA</a> available.</p>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ sudo add-apt-repository ppa:chris-lea/node.js
|
||||
$ sudo apt-get update
|
||||
$ sudo apt-get install nodejs</pre>
|
||||
</div>
|
||||
<p>As <code>v8</code> is written in C++ and comes as a C++ library it is crucial to compile your module using the same compiler flags as used for building v8. To make things easier, <code>node.js</code> provides a build tool called <code>node-gyp</code>.</p>
|
||||
<p>You have to install it using <code>npm</code>:</p>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ sudo npm install -g node-gyp</pre>
|
||||
</div>
|
||||
<p><code>node-gyp</code> expects a configuration file named <code>binding.gyp</code> which is basically in JSON format and conforms to the same format that is used with Google's build-tool <code>gyp</code>.</p>
|
||||
<p><code>binding.gyp</code>:</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
{
|
||||
"targets": [
|
||||
{
|
||||
"target_name": "example",
|
||||
"sources": [ "example.cxx", "example_wrap.cxx" ]
|
||||
}
|
||||
]
|
||||
}</pre>
|
||||
</div>
|
||||
<p>First create the wrapper using SWIG:</p>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ swig -javascript -node -c++ example.i</pre>
|
||||
</div>
|
||||
<p>Then run <code>node-gyp build</code> to actually create the module:</p>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ node-gyp build</pre>
|
||||
</div>
|
||||
<p>This will create a <code>build</code> folder containing the native module. To use the extension you need to 'require' it in your Javascript source file:</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
require("./build/Release/example")</pre>
|
||||
</div>
|
||||
<p>A more detailed explanation is given in the <a href="#Javascript_examples">Examples</a> section.</p>
|
||||
|
||||
<H4><a name="Javascript_troubleshooting">27.3.1.1 Troubleshooting</a></H4>
|
||||
|
||||
|
||||
<ul>
|
||||
<li><em>'module' object has no attribute 'script_main'</em></li>
|
||||
</ul>
|
||||
<p>This error happens when <code>gyp</code> is installed as a distribution package. It seems to be outdated. Removing it resolves the problem.</p>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ sudo apt-get remove gyp</pre>
|
||||
</div>
|
||||
|
||||
<H3><a name="Javascript_embedded_webkit">27.3.2 Embedded Webkit</a></H3>
|
||||
|
||||
|
||||
<p>Webkit is pre-installed on Mac OS X and available as a library for GTK.</p>
|
||||
|
||||
<H4><a name="Javascript_osx">27.3.2.1 Mac OS X</a></H4>
|
||||
|
||||
|
||||
<p>There is general information about programming with WebKit on <a href="https://developer.apple.com/library/mac/documentation/cocoa/conceptual/DisplayWebContent/DisplayWebContent.html">Apple Developer Documentation</a>. Details about <code>Cocoa</code> programming are not covered here.</p>
|
||||
<p>An integration of a native extension 'example' would look like this:</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
#import "appDelegate.h"
|
||||
|
||||
extern bool example_initialize(JSGlobalContextRef context, JSObjectRef* exports);
|
||||
|
||||
|
||||
@implementation ExampleAppDelegate
|
||||
|
||||
@synthesize webView;
|
||||
|
||||
- (void)addGlobalObject:(JSContextRef) context:(NSString *)objectName:(JSObjectRef) theObject {
|
||||
JSObjectRef global = JSContextGetGlobalObject(context);
|
||||
JSStringRef objectJSName = JSStringCreateWithCFString( (CFStringRef) objectName )
|
||||
if ( objectJSName != NULL ) {
|
||||
JSObjectSetProperty(context, global, objectJSName, theObject, kJSPropertyAttributeReadOnly, NULL);
|
||||
JSStringRelease( objectJSName );
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
||||
|
||||
// Start a webview with the bundled index.html file
|
||||
NSString *path = [[NSBundle mainBundle] bundlePath];
|
||||
NSString *url = [NSString stringWithFormat: @"file://%@/Contents/Assets/index.html", path];
|
||||
|
||||
WebFrame *webframe = [webView mainFrame];
|
||||
JSGlobalContextRef context = [webframe globalContext];
|
||||
|
||||
JSObjectRef example;
|
||||
example_initialize(context, &example);
|
||||
[self addGlobalObject:context:@"example":example]
|
||||
|
||||
JSObjectSetProperty(context, global, JSStringRef propertyName, example, JSPropertyAttributes attributes, NULL);
|
||||
|
||||
[ [webView mainFrame] loadRequest:
|
||||
[NSURLRequest requestWithURL: [NSURL URLWithString:url] ]
|
||||
];
|
||||
}
|
||||
|
||||
@end</pre>
|
||||
</div>
|
||||
|
||||
<H4><a name="Javascript_gtk">27.3.2.2 GTK</a></H4>
|
||||
|
||||
|
||||
<p>There is general information about programming GTK at <a href="https://developer.gnome.org/gtk2/">GTK documentation</a> and in the <a href="https://developer.gnome.org/gtk-tutorial/">GTK tutorial</a>, and for Webkit there is a <a href="http://webkitgtk.org/reference/webkitgtk/stable/index.html">Webkit GTK+ API Reference</a>.</p>
|
||||
<p>An integration of a native extension 'example' would look like this:</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
#include <gtk/gtk.h>
|
||||
#include <webkit/webkit.h>
|
||||
|
||||
extern bool example_initialize(JSGlobalContextRef context);
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
// Initialize GTK+
|
||||
gtk_init(&argc, &argv);
|
||||
|
||||
...
|
||||
|
||||
// Create a browser instance
|
||||
WebKitWebView *webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
|
||||
WebFrame *webframe = webkit_web_view_get_main_frame(webView);
|
||||
JSGlobalContextRef context = webkit_web_frame_get_global_context(webFrame);
|
||||
JSObjectRef global = JSContextGetGlobalObject(context);
|
||||
|
||||
JSObjectRef exampleModule;
|
||||
example_initialize(context, &exampleModule);
|
||||
JSStringRef jsName = JSStringCreateWithUTF8CString("example");
|
||||
JSObjectSetProperty(context, global, jsName, exampleModule, kJSPropertyAttributeReadOnly, NULL);
|
||||
JSStringRelease(jsName);
|
||||
|
||||
...
|
||||
|
||||
// Load a web page into the browser instance
|
||||
webkit_web_view_load_uri(webView, "http://www.webkitgtk.org/");
|
||||
|
||||
...
|
||||
|
||||
// Run the main GTK+ event loop
|
||||
gtk_main();
|
||||
|
||||
return 0;
|
||||
}</pre>
|
||||
</div>
|
||||
|
||||
<H3><a name="Javascript_applications_webkit">27.3.3 Creating Applications with node-webkit</a></H3>
|
||||
|
||||
|
||||
<p>To get started with <code>node-webkit</code> there is a very informative set of <a href="https://github.com/rogerwang/node-webkit/wiki">wiki pages</a>.</p>
|
||||
<p>Similar to <code>node.js</code>, <code>node-webkit</code> is started from command line within a <code>node.js</code> project directory.
|
||||
Native extensions are created in the very same way as for <code>node.js</code>, except that a customized <code>gyp</code> derivate has to be used: <a href="https://github.com/rogerwang/nw-gyp">nw-gyp</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A simple example would have the following structure:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
- package.json
|
||||
- app.html
|
||||
- app.js
|
||||
- node_modules
|
||||
/ example
|
||||
... (as known from node.js)
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The configuration file essentially conforms to <code>node.js</code> syntax.
|
||||
It has some extras to configure <code>node-webkit</code>. See the <a href="https://github.com/rogerwang/node-webkit/wiki/Manifest-format">Manifest</a> specification for more details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<code>package.json</code>:
|
||||
</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
{
|
||||
"name": "example",
|
||||
"main": "app.html",
|
||||
"window": {
|
||||
"show": true,
|
||||
"width": 800,
|
||||
"height": 600
|
||||
}
|
||||
}</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The <code>'main'</code> property of <code>package.json</code> specifies a web-page to be rendered in
|
||||
the main window.</p>
|
||||
|
||||
<p>
|
||||
<code>app.html</code>:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
<html>
|
||||
<head>
|
||||
<script src="app.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
The greatest common divisor of
|
||||
<span id="x"></span> and
|
||||
<span id="y"></span> is
|
||||
<span id="z"></span>.
|
||||
</div>
|
||||
</body>
|
||||
</html></pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
As known from <code>node.js</code> one can use <code>require</code> to load javascript modules.
|
||||
Additionally, <code>node-webkit</code> provides an API that allows to manipulate the window's menu,
|
||||
open new windows, and many more things.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<code>app.js</code>:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>window.onload = function() {
|
||||
var example = require("example");
|
||||
var x = 18;
|
||||
var y = 24;
|
||||
var z = example.gcd(x, y);
|
||||
document.querySelector('#x').innerHTML = x;
|
||||
document.querySelector('#y').innerHTML = y;
|
||||
document.querySelector('#z').innerHTML = z;
|
||||
};</pre>
|
||||
</div>
|
||||
|
||||
<H2><a name="Javascript_examples">27.4 Examples</a></H2>
|
||||
|
||||
|
||||
<p>Some basic examples are shown here in more detail.</p>
|
||||
|
||||
<H3><a name="Javascript_simple_example">27.4.1 Simple</a></H3>
|
||||
|
||||
|
||||
<p>The common example <code>simple</code> looks like this:</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
/* File : example.i */
|
||||
%module example
|
||||
|
||||
%inline %{
|
||||
extern int gcd(int x, int y);
|
||||
extern double Foo;
|
||||
%}</pre>
|
||||
</div>
|
||||
<p>To make this available as a node extension a <code>binding.gyp</code> has to be created:</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
{
|
||||
"targets": [
|
||||
{
|
||||
"target_name": "example",
|
||||
"sources": [ "example.cxx", "example_wrap.cxx" ]
|
||||
}
|
||||
]
|
||||
}</pre>
|
||||
</div>
|
||||
<p>Then <code>node-gyp</code> is used to build the extension:</p>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ node-gyp configure build</pre>
|
||||
</div>
|
||||
<p>From a 'nodejs` application the extension would be used like this:</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
// import the extension via require
|
||||
var example = require("./build/Release/example");
|
||||
|
||||
// calling the global method
|
||||
var x = 42;
|
||||
var y = 105;
|
||||
var g = example.gcd(x, y);
|
||||
|
||||
// Accessing the global variable
|
||||
var f = example.Foo;
|
||||
example.Foo = 3.1415926;</pre>
|
||||
</div>
|
||||
<p>First the module <code>example</code> is loaded from the previously built extension. Global methods and variables are available in the scope of the module.</p>
|
||||
|
||||
<p><b>Note</b>: ECMAScript 5, the currently implemented Javascript standard, does not have modules. <code>node.js</code> and other implementations provide this mechanism defined by the <a href="http://wiki.commonjs.org/wiki/CommonJS">CommonJS</a> group. For browsers this is provided by <a href="http://browserify.org">Browserify</a>, for instance.</p>
|
||||
|
||||
<H3><a name="Javascript_class_example">27.4.2 Class</a></H3>
|
||||
|
||||
|
||||
<p>The common example <code>class</code> defines three classes, <code>Shape</code>, <code>Circle</code>, and <code>Square</code>:</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
class Shape {
|
||||
public:
|
||||
Shape() {
|
||||
nshapes++;
|
||||
}
|
||||
virtual ~Shape() {
|
||||
nshapes--;
|
||||
}
|
||||
double x, y;
|
||||
void move(double dx, double dy);
|
||||
virtual double area(void) = 0;
|
||||
virtual double perimeter(void) = 0;
|
||||
static int nshapes;
|
||||
};
|
||||
|
||||
class Circle : public Shape {
|
||||
private:
|
||||
double radius;
|
||||
public:
|
||||
Circle(double r) : radius(r) { }
|
||||
virtual double area(void);
|
||||
virtual double perimeter(void);
|
||||
};
|
||||
|
||||
class Square : public Shape {
|
||||
private:
|
||||
double width;
|
||||
public:
|
||||
Square(double w) : width(w) { }
|
||||
virtual double area(void);
|
||||
virtual double perimeter(void);
|
||||
};</pre>
|
||||
</div>
|
||||
<p><code>Circle</code> and <code>Square</code> inherit from <code>Shape</code>. <code>Shape</code> has a static variable <code>nshapes</code>, a function <code>move</code> that can't be overridden (non-virtual), and two abstract functions <code>area</code> and <code>perimeter</code> (pure virtual) that must be overridden by the sub-classes.</p>
|
||||
<p>A <code>nodejs</code> extension is built the same way as for the <code>simple</code> example.</p>
|
||||
<p>In Javascript it can be used as follows:</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
var example = require("./build/Release/example");
|
||||
|
||||
// local aliases for convenience
|
||||
var Shape = example.Shape;
|
||||
var Circle = example.Circle;
|
||||
var Square = example.Square;
|
||||
|
||||
// creating new instances using the 'new' operator
|
||||
var c = new Circle(10);
|
||||
var s = new Square(10);
|
||||
|
||||
// accessing a static member
|
||||
Shape.nshapes;
|
||||
|
||||
// accessing member variables
|
||||
c.x = 20;
|
||||
c.y = 30;
|
||||
s.x = -10;
|
||||
s.y = 5;
|
||||
|
||||
// calling some methods
|
||||
c.area();
|
||||
c.perimeter();
|
||||
s.area();
|
||||
s.perimeter();
|
||||
|
||||
// instantiation of Shape is not permitted
|
||||
new Shape();</pre>
|
||||
</div>
|
||||
<p>Running these commands in an interactive node shell results in the following output:</p>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ node -i
|
||||
& var example = require("./build/Release/example");
|
||||
undefined
|
||||
& var Shape = example.Shape;
|
||||
undefined
|
||||
& var Circle = example.Circle;
|
||||
undefined
|
||||
& var Square = example.Square;
|
||||
undefined
|
||||
& var c = new Circle(10);
|
||||
undefined
|
||||
& var s = new Square(10);
|
||||
undefined
|
||||
& Shape.nshapes;
|
||||
2
|
||||
& c.x = 20;
|
||||
20
|
||||
& c.y = 30;
|
||||
30
|
||||
& s.x = -10;
|
||||
-10
|
||||
& s.y = 5;
|
||||
5
|
||||
& c.area();
|
||||
314.1592653589793
|
||||
& c.perimeter();
|
||||
62.83185307179586
|
||||
& s.area();
|
||||
100
|
||||
& s.perimeter();
|
||||
40
|
||||
& c.move(40, 40)
|
||||
undefined
|
||||
& c.x
|
||||
60
|
||||
& c.y
|
||||
70
|
||||
& new Shape()
|
||||
Error: Class Shape can not be instantiated
|
||||
at repl:1:2
|
||||
at REPLServer.self.eval (repl.js:110:21)
|
||||
at Interface.<anonymous> (repl.js:239:12)
|
||||
at Interface.EventEmitter.emit (events.js:95:17)
|
||||
at Interface._onLine (readline.js:202:10)
|
||||
at Interface._line (readline.js:531:8)
|
||||
at Interface._ttyWrite (readline.js:760:14)
|
||||
at ReadStream.onkeypress (readline.js:99:10)
|
||||
at ReadStream.EventEmitter.emit (events.js:98:17)
|
||||
at emitKey (readline.js:1095:12)</pre>
|
||||
</div>
|
||||
<p>
|
||||
<b>Note</b>: In ECMAScript 5 there is no concept for classes. Instead each function can be used as a constructor function which is executed by the 'new' operator. Furthermore, during construction the key property <code>prototype</code> of the constructor function is used to attach a prototype instance to the created object. A prototype is essentially an object itself that is the first-class delegate of a class used whenever the access to a property of an object fails. The very same prototype instance is shared among all instances of one type. Prototypal inheritance is explained in more detail on in <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain">Inheritance and the prototype chain</a>, for instance.
|
||||
</p>
|
||||
|
||||
<H2><a name="Javascript_implementation">27.5 Implementation</a></H2>
|
||||
|
||||
|
||||
<p>The Javascript Module implementation has taken a very different approach compared to other language modules in order to support different Javascript interpreters.</p>
|
||||
|
||||
<H3><a name="Javascript_source_code">27.5.1 Source Code</a></H3>
|
||||
|
||||
|
||||
<p>The Javascript module is implemented in <code>Source/Modules/javascript.cxx</code>. It dispatches the code generation to a <code>JSEmitter</code> instance, <code>V8Emitter</code> or <code>JSCEmitter</code>. Additionally there are some helpers: <code>Template</code>, for templated code generation, and <code>JSEmitterState</code>, which is used to manage state information during AST traversal. This rough map shall make it easier to find a way through this huge source file:</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
// module wide defines
|
||||
|
||||
#define NAME "name"
|
||||
...
|
||||
|
||||
// ###############################
|
||||
// # Helper class declarations
|
||||
|
||||
class JSEmitterState { ... };
|
||||
|
||||
class Template { ... };
|
||||
|
||||
// ###############################
|
||||
// # JSEmitter declaration
|
||||
|
||||
class JSEmitter { ... };
|
||||
|
||||
// Emitter factory declarations
|
||||
|
||||
JSEmitter *swig_javascript_create_JSCEmitter();
|
||||
JSEmitter *swig_javascript_create_V8Emitter();
|
||||
|
||||
// ###############################
|
||||
// # Javascript module
|
||||
|
||||
// Javascript module declaration
|
||||
|
||||
class JAVASCRIPT:public Language { ... };
|
||||
|
||||
// Javascript module implementation
|
||||
|
||||
int JAVASCRIPT::functionWrapper(Node *n) { ... }
|
||||
...
|
||||
|
||||
// Module factory implementation
|
||||
|
||||
static Language *new_swig_javascript() { ... }
|
||||
|
||||
extern "C" Language *swig_javascript(void) { ... }
|
||||
|
||||
// ###############################
|
||||
// # JSEmitter base implementation
|
||||
|
||||
JSEmitter::JSEmitter() { ... }
|
||||
|
||||
Template JSEmitter::getTemplate(const String *name) { ... }
|
||||
...
|
||||
|
||||
// ###############################
|
||||
// # JSCEmitter
|
||||
|
||||
// JSCEmitter declaration
|
||||
|
||||
class JSCEmitter: public JSEmitter { ... };
|
||||
|
||||
// JSCEmitter implementation
|
||||
|
||||
JSCEmitter::JSCEmitter() { ... }
|
||||
|
||||
void JSCEmitter::marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static) { ... }
|
||||
...
|
||||
|
||||
// JSCEmitter factory
|
||||
|
||||
JSEmitter *swig_javascript_create_JSCEmitter() { ... }
|
||||
|
||||
|
||||
// ###############################
|
||||
// # V8Emitter
|
||||
|
||||
// V8Emitter declaration
|
||||
|
||||
class V8Emitter: public JSEmitter { ... };
|
||||
|
||||
// V8Emitter implementation
|
||||
|
||||
V8Emitter::V8Emitter() { ... }
|
||||
|
||||
int V8Emitter::initialize(Node *n) { ... }
|
||||
|
||||
// V8Emitter factory
|
||||
|
||||
JSEmitter *swig_javascript_create_V8Emitter() { ... }
|
||||
|
||||
|
||||
// ###############################
|
||||
// # Helper implementation (JSEmitterState, Template)
|
||||
|
||||
JSEmitterState::JSEmitterState() { ... }
|
||||
...
|
||||
|
||||
Template::Template(const String *code_) { ... }
|
||||
...</pre>
|
||||
</div>
|
||||
|
||||
<H3><a name="Javascript_code_templates">27.5.2 Code Templates</a></H3>
|
||||
|
||||
|
||||
<p>All generated code is created on the basis of code templates. The templates for <em>JavascriptCore</em> can be found in <code>Lib/javascript/jsc/javascriptcode.swg</code>, for <em>v8</em> in <code>Lib/javascript/v8/javascriptcode.swg</code>.</p>
|
||||
<p>To track the originating code template for generated code you can run</p>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
$ swig -javascript -jsc -debug-codetemplates</pre>
|
||||
</div>
|
||||
<p>which wraps generated code with a descriptive comment</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
/* begin fragment("template_name") */
|
||||
|
||||
...generated code ...
|
||||
|
||||
/* end fragment("template_name") */</pre>
|
||||
</div>
|
||||
<p>The Template class is used like this:</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
Template t_register = getTemplate("jsv8_register_static_variable");
|
||||
t_register.replace("$jsparent", state.clazz(NAME_MANGLED))
|
||||
.replace("$jsname", state.variable(NAME))
|
||||
.replace("$jsgetter", state.variable(GETTER))
|
||||
.replace("$jssetter", state.variable(SETTER))
|
||||
.trim().
|
||||
print(f_init_static_wrappers);</pre>
|
||||
</div>
|
||||
<p>A code template is registered with the <em>JSEmitter</em> via <code>fragment(name, "template")</code>, e.g., </p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
%fragment ("jsc_variable_declaration", "templates")
|
||||
%{
|
||||
{"$jsname", $jsgetter, $jssetter, kJSPropertyAttributeNone},
|
||||
%}</pre>
|
||||
</div>
|
||||
<p><code>Template</code> creates a copy of that string and <code>Template::replace</code> uses Swig's <code>Replaceall</code> to replace variables in the template. <code>Template::trim</code> can be used to eliminate leading and trailing whitespaces. <code>Template::print</code> is used to write the final template string to a Swig <code>DOH</code> (based on <code>Printv</code>). All methods allow chaining.</p>
|
||||
|
||||
<H3><a name="Javascript_emitter">27.5.3 Emitter</a></H3>
|
||||
|
||||
|
||||
<p>The Javascript module delegates code generation to a <code>JSEmitter</code> instance. The following extract shows the essential interface:</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
class JSEmitter {
|
||||
...
|
||||
|
||||
/**
|
||||
* Opens output files and temporary output DOHs.
|
||||
*/
|
||||
virtual int initialize(Node *n);
|
||||
|
||||
/**
|
||||
* Writes all collected code into the output file(s).
|
||||
*/
|
||||
virtual int dump(Node *n) = 0;
|
||||
|
||||
/**
|
||||
* Cleans up all open output DOHs.
|
||||
*/
|
||||
virtual int close() = 0;
|
||||
|
||||
...
|
||||
|
||||
/**
|
||||
* Invoked at the beginning of the classHandler.
|
||||
*/
|
||||
virtual int enterClass(Node *);
|
||||
|
||||
/**
|
||||
* Invoked at the end of the classHandler.
|
||||
*/
|
||||
virtual int exitClass(Node *) {
|
||||
return SWIG_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked at the beginning of the variableHandler.
|
||||
*/
|
||||
virtual int enterVariable(Node *);
|
||||
|
||||
/**
|
||||
* Invoked at the end of the variableHandler.
|
||||
*/
|
||||
virtual int exitVariable(Node *) {
|
||||
return SWIG_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked at the beginning of the functionHandler.
|
||||
*/
|
||||
virtual int enterFunction(Node *);
|
||||
|
||||
/**
|
||||
* Invoked at the end of the functionHandler.
|
||||
*/
|
||||
virtual int exitFunction(Node *) {
|
||||
return SWIG_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by functionWrapper callback after call to Language::functionWrapper.
|
||||
*/
|
||||
virtual int emitWrapperFunction(Node *n);
|
||||
|
||||
/**
|
||||
* Invoked from constantWrapper after call to Language::constantWrapper.
|
||||
**/
|
||||
virtual int emitConstant(Node *n);
|
||||
|
||||
/**
|
||||
* Registers a given code snippet for a given key name.
|
||||
*
|
||||
* This method is called by the fragmentDirective handler
|
||||
* of the JAVASCRIPT language module.
|
||||
**/
|
||||
int registerTemplate(const String *name, const String *code);
|
||||
|
||||
/**
|
||||
* Retrieve the code template registered for a given name.
|
||||
*/
|
||||
Template getTemplate(const String *name);
|
||||
|
||||
State &getState();
|
||||
|
||||
...
|
||||
|
||||
}</pre>
|
||||
</div>
|
||||
<p>The module calls <code>initialize</code>, <code>dump</code>, and <code>close</code> from within the <code>top</code> method:</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
int JAVASCRIPT::top(Node *n) {
|
||||
emitter->initialize(n);
|
||||
|
||||
Language::top(n);
|
||||
|
||||
emitter->dump(n);
|
||||
emitter->close();
|
||||
|
||||
return SWIG_OK;
|
||||
}</pre>
|
||||
</div>
|
||||
<p>The methods <code>enterClass</code> and <code>exitClass</code> are called from within the <code>classHandler</code> method:</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
int JAVASCRIPT::classHandler(Node *n) {
|
||||
|
||||
emitter->enterClass(n);
|
||||
Language::classHandler(n);
|
||||
emitter->exitClass(n);
|
||||
|
||||
return SWIG_OK;
|
||||
}</pre>
|
||||
</div>
|
||||
<p>In <code>enterClass</code> the emitter stores state information that is necessary when processing class members. In <code>exitClass</code> the wrapper code for the whole class is generated.</p>
|
||||
|
||||
<H3><a name="Javascript_emitter_states">27.5.4 Emitter states</a></H3>
|
||||
|
||||
|
||||
<p>For storing information during the AST traversal the emitter provides a <code>JSEmitterState</code> with different slots to store data representing the scopes global, class, function, and variable.</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
class JSEmitterState {
|
||||
|
||||
public:
|
||||
|
||||
JSEmitterState();
|
||||
|
||||
~JSEmitterState();
|
||||
|
||||
DOH *global();
|
||||
|
||||
DOH *global(const char* key, DOH *initial = 0);
|
||||
|
||||
DOH *clazz(bool reset = false);
|
||||
|
||||
DOH *clazz(const char* key, DOH *initial = 0);
|
||||
|
||||
DOH *function(bool reset = false);
|
||||
|
||||
DOH *function(const char* key, DOH *initial = 0);
|
||||
|
||||
DOH *variable(bool reset = false);
|
||||
|
||||
DOH *variable(const char* key, DOH *initial = 0);
|
||||
|
||||
static int IsSet(DOH *val);
|
||||
|
||||
...
|
||||
};</pre>
|
||||
</div>
|
||||
<p>When entering a scope, such as in <code>enterClass</code>, the corresponding state is reset and new data is stored:</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
state.clazz(RESET);
|
||||
state.clazz(NAME, Getattr(n, "sym:name"));</pre>
|
||||
</div>
|
||||
<p>State information can be retrieved using <code>state.clazz(NAME)</code> or with <code>Getattr</code> on <code>state.clazz()</code> which actually returns a <code>Hash</code> instance.</p>
|
||||
|
||||
|
||||
<H3><a name="Javascript_jsc_exceptions">27.5.5 Handling Exceptions in JavascriptCore</a></H3>
|
||||
|
||||
|
||||
<p>Applications with an embedded JavascriptCore should be able to present detailed exception messages that occur in the Javascript engine. Below is an example derived from code provided by Brian Barnes on how these exception details can be extracted.</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
void script_exception_to_string(JSContextRef js_context, JSValueRef exception_value_ref, char* return_error_string, int return_error_string_max_length)
|
||||
{
|
||||
JSObjectRef exception_object;
|
||||
JSValueRef value_ref;
|
||||
JSStringRef jsstring_property_name = NULL;
|
||||
JSValueRef temporary_exception = NULL;
|
||||
JSStringRef js_return_string = NULL;
|
||||
size_t bytes_needed;
|
||||
char* c_result_string = NULL;
|
||||
exception_object = JSValueToObject(js_context, exception_value_ref, NULL);
|
||||
|
||||
/* source url */
|
||||
strcpy(return_error_string, "[");
|
||||
jsstring_property_name = JSStringCreateWithUTF8CString("sourceURL");
|
||||
value_ref = JSObjectGetProperty(js_context, exception_object, jsstring_property_name, &temporary_exception);
|
||||
JSStringRelease(jsstring_property_name);
|
||||
js_return_string = JSValueToStringCopy(js_context, value_ref, NULL);
|
||||
bytes_needed = JSStringGetMaximumUTF8CStringSize(js_return_string);
|
||||
c_result_string = (char*)calloc(bytes_needed, sizeof(char));
|
||||
JSStringGetUTF8CString(js_return_string, c_result_string, bytes_needed);
|
||||
JSStringRelease(js_return_string);
|
||||
strncat(return_error_string, c_result_string, return_error_string_max_length-1);
|
||||
free(c_result_string);
|
||||
|
||||
strncat(return_error_string, ":", return_error_string_max_length-1);
|
||||
|
||||
/* line number */
|
||||
|
||||
jsstring_property_name = JSStringCreateWithUTF8CString("line");
|
||||
value_ref = JSObjectGetProperty(js_context, exception_object, jsstring_property_name, &temporary_exception);
|
||||
JSStringRelease(jsstring_property_name);
|
||||
js_return_string = JSValueToStringCopy(js_context, value_ref, NULL);
|
||||
bytes_needed = JSStringGetMaximumUTF8CStringSize(js_return_string);
|
||||
c_result_string = (char*)calloc(bytes_needed, sizeof(char));
|
||||
JSStringGetUTF8CString(js_return_string, c_result_string, bytes_needed);
|
||||
JSStringRelease(js_return_string);
|
||||
strncat(return_error_string, c_result_string, return_error_string_max_length-1);
|
||||
free(c_result_string);
|
||||
|
||||
strncat(return_error_string, "]", return_error_string_max_length-1);
|
||||
|
||||
/* error message */
|
||||
|
||||
jsstring_property_name = JSStringCreateWithUTF8CString("message");
|
||||
value_ref = JSObjectGetProperty(js_context, exception_object, jsstring_property_name, &temporary_exception);
|
||||
JSStringRelease(jsstring_property_name);
|
||||
if(NULL == value_ref)
|
||||
{
|
||||
strncat(return_error_string, "Unknown Error", return_error_string_max_length-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
js_return_string = JSValueToStringCopy(js_context, value_ref, NULL);
|
||||
bytes_needed = JSStringGetMaximumUTF8CStringSize(js_return_string);
|
||||
c_result_string = (char*)calloc(bytes_needed, sizeof(char));
|
||||
JSStringGetUTF8CString(js_return_string, c_result_string, bytes_needed);
|
||||
JSStringRelease(js_return_string);
|
||||
strncat(return_error_string, c_result_string, return_error_string_max_length-1);
|
||||
free(c_result_string);
|
||||
}
|
||||
}</pre>
|
||||
</div>
|
||||
|
||||
<p>It would be used in the following way:</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
if(js_exception)
|
||||
{
|
||||
char return_error_string[256];
|
||||
script_exception_to_string(js_context, js_exception, return_error_string, 256);
|
||||
printf("Compile error is %s", return_error_string);
|
||||
}</pre>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,604 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and Common Lisp</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<H1><a name="Lisp">29 SWIG and Common Lisp</a></H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#Lisp_nn3">Common Foreign Function Interface(CFFI)</a>
|
||||
<ul>
|
||||
<li><a href="#Lisp_nn4">Additional Commandline Options </a>
|
||||
<li><a href="#Lisp_nn5">Generating CFFI bindings</a>
|
||||
<li><a href="#Lisp_nn6">Generating CFFI bindings for C++ code</a>
|
||||
<li><a href="#Lisp_nn7">Inserting user code into generated files</a>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a href="#Lisp_nn9">Additional Commandline Options </a>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
Common Lisp is a high-level, all-purpose, object-oriented,
|
||||
dynamic, functional programming language with long history.
|
||||
Common Lisp is used in many fields, ranging from web development to
|
||||
finance, and also common in computer science education.
|
||||
There are more than 9 different implementations of common lisp which
|
||||
are available, all have different foreign function
|
||||
interfaces. SWIG currently supports the
|
||||
Common Foreign Function Interface(CFFI).
|
||||
</p>
|
||||
|
||||
<H2><a name="Lisp_nn3">29.2 Common Foreign Function Interface(CFFI)</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
CFFI, the Common Foreign Function Interface, is a portable foreign
|
||||
function interface for ANSI Common Lisp systems.
|
||||
CFFI requires only a small set of
|
||||
low-level functionality from the Lisp implementation, such as
|
||||
calling a foreign function by name, allocating foreign memory,
|
||||
and dereferencing pointers.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To run the cffi module of SWIG requires very little effort, you
|
||||
just need to run:
|
||||
</p>
|
||||
<div class="code"><pre>
|
||||
swig -cffi -module <i>module-name</i> <i>file-name</i>
|
||||
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
But a better was of using all the power of SWIG is to write SWIG
|
||||
interface files. Below we will explain how to write interface
|
||||
files and the various things which you can do with them.
|
||||
</p>
|
||||
|
||||
<H3><a name="Lisp_nn4">29.2.1 Additional Commandline Options </a></H3>
|
||||
|
||||
|
||||
<table summary="CFFI specific options">
|
||||
<tr>
|
||||
<th> CFFI specific options</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-generate-typedef</td>
|
||||
<td>If this option is given then defctype will be used to generate<br/>
|
||||
shortcuts according to the typedefs in the input.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-[no]cwrap</td>
|
||||
<td>Turn on or turn off generation of an intermediate C file when<br/>
|
||||
creating a C interface. By default this is only done for C++ code.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-[no]swig-lisp</td>
|
||||
<td>Turns on or off generation of code for helper lisp macro, functions,
|
||||
etc. which SWIG uses while generating wrappers. These macros, functions
|
||||
may still be used by generated wrapper code.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<H3><a name="Lisp_nn5">29.2.2 Generating CFFI bindings</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
||||
As we mentioned earlier the ideal way to use SWIG is to use interface
|
||||
files. To illustrate the use of it, let's assume that we have a
|
||||
file named <i>test.h</i> with the following C code:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
#define y 5
|
||||
#define x (y >> 1)
|
||||
|
||||
typedef int days;
|
||||
|
||||
struct bar {
|
||||
short p, q;
|
||||
char a, b;
|
||||
int *z[1000];
|
||||
struct bar * n;
|
||||
};
|
||||
|
||||
struct bar * my_struct;
|
||||
|
||||
struct foo {
|
||||
int a;
|
||||
struct foo * b[100];
|
||||
};
|
||||
|
||||
int pointer_func(void (*ClosureFun)( void* _fun, void* _data, void* _evt ), int p);
|
||||
|
||||
int func123(div_t * p, int **q[100], int r[][1000][10]);
|
||||
|
||||
void lispsort_double (int n, double * array);
|
||||
|
||||
enum color { RED, BLUE, GREEN};
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Corresponding to this we will write a simple interface file:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%module test
|
||||
|
||||
%include "test.h"
|
||||
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
The generated SWIG Code will be:
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
;;;SWIG wrapper code starts here
|
||||
|
||||
(cl:defmacro defanonenum (&body enums)
|
||||
"Converts anonymous enums to defconstants."
|
||||
`(cl:progn , @(cl:loop for value in enums
|
||||
for index = 0 then (cl:1+ index)
|
||||
when (cl:listp value) do (cl:setf index (cl:second value)
|
||||
value (cl:first value))
|
||||
collect `(cl:defconstant , value , index))))
|
||||
|
||||
(cl:eval-when (:compile-toplevel :load-toplevel)
|
||||
(cl:unless (cl:fboundp 'swig-lispify)
|
||||
(cl:defun swig-lispify (name flag cl:&optional (package cl:*package*))
|
||||
(cl:labels ((helper (lst last rest cl:&aux (c (cl:car lst)))
|
||||
(cl:cond
|
||||
((cl:null lst)
|
||||
rest)
|
||||
((cl:upper-case-p c)
|
||||
(helper (cl:cdr lst) 'upper
|
||||
(cl:case last
|
||||
((lower digit) (cl:list* c #\- rest))
|
||||
(cl:t (cl:cons c rest)))))
|
||||
((cl:lower-case-p c)
|
||||
(helper (cl:cdr lst) 'lower (cl:cons (cl:char-upcase c) rest)))
|
||||
((cl:digit-char-p c)
|
||||
(helper (cl:cdr lst) 'digit
|
||||
(cl:case last
|
||||
((upper lower) (cl:list* c #\- rest))
|
||||
(cl:t (cl:cons c rest)))))
|
||||
((cl:char-equal c #\_)
|
||||
(helper (cl:cdr lst) '_ (cl:cons #\- rest)))
|
||||
(cl:t
|
||||
(cl:error "Invalid character: ~A" c)))))
|
||||
(cl:let ((fix (cl:case flag
|
||||
((constant enumvalue) "+")
|
||||
(variable "*")
|
||||
(cl:t ""))))
|
||||
(cl:intern
|
||||
(cl:concatenate
|
||||
'cl:string
|
||||
fix
|
||||
(cl:nreverse (helper (cl:concatenate 'cl:list name) cl:nil cl:nil))
|
||||
fix)
|
||||
package))))))
|
||||
|
||||
;;;SWIG wrapper code ends here
|
||||
|
||||
|
||||
(cl:defconstant y 5)
|
||||
|
||||
(cl:defconstant x (cl:ash 5 -1))
|
||||
|
||||
(cffi:defcstruct bar
|
||||
(p :short)
|
||||
(q :short)
|
||||
(a :char)
|
||||
(b :char)
|
||||
(z :pointer)
|
||||
(n :pointer))
|
||||
|
||||
(cffi:defcvar ("my_struct" my_struct)
|
||||
:pointer)
|
||||
|
||||
(cffi:defcstruct foo
|
||||
(a :int)
|
||||
(b :pointer))
|
||||
|
||||
(cffi:defcfun ("pointer_func" pointer_func) :int
|
||||
(ClosureFun :pointer)
|
||||
(p :int))
|
||||
|
||||
(cffi:defcfun ("func123" func123) :int
|
||||
(p :pointer)
|
||||
(q :pointer)
|
||||
(r :pointer))
|
||||
|
||||
(cffi:defcfun ("lispsort_double" lispsort_double) :void
|
||||
(n :int)
|
||||
(array :pointer))
|
||||
|
||||
(cffi:defcenum color
|
||||
:RED
|
||||
:BLUE
|
||||
:GREEN)
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
The <i>SWIG wrapper</i> code refers to the special code which SWIG
|
||||
may need to use while wrapping C code. You can turn on/off the
|
||||
generation of this code by using the <i>-[no]swig-lisp</i>
|
||||
option. You must have noticed that SWIG goes one extra step to
|
||||
ensure that CFFI does not do automatic lispification of the C
|
||||
function names. The reason SWIG does this is because quite often
|
||||
developers want to build a nice CLOS based lispy API, and this one
|
||||
to one correspondence between C function names and lisp function
|
||||
name helps.
|
||||
</p>
|
||||
|
||||
<p> Maybe you want to have your own convention for generating lisp
|
||||
function names for corresponding C function names, or you just
|
||||
want to lispify the names, also, before we forget you want to
|
||||
export the generated lisp names. To do this, we will use the
|
||||
SWIG <a
|
||||
href="Customization.html#Customization_features">feature directive</a>.
|
||||
Let's edit the interface file such that the C type "div_t*" is changed
|
||||
to Lisp type ":my-pointer", we lispify all names,
|
||||
export everything, and do some more stuff.
|
||||
|
||||
</p>
|
||||
<div class="code"><pre>
|
||||
%module test
|
||||
|
||||
%typemap(cin) div_t* ":my-pointer";
|
||||
|
||||
%feature("intern_function", "1");
|
||||
%feature("export");
|
||||
|
||||
%feature("inline") lispsort_double;
|
||||
%feature("intern_function", "my-lispify") lispsort_double;
|
||||
%feature("export", package="'some-other-package") lispsort_double;
|
||||
|
||||
%rename func123 renamed_cool_func;
|
||||
|
||||
%ignore "pointer_func";
|
||||
|
||||
%include "test.h"
|
||||
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
The <i>typemap(cin)</i> ensures that for all arguments which are input
|
||||
to C with the type "div_t*", the ":my-pointer" type be
|
||||
used. Similarly <i>typemap(cout)</i> are used for all types which
|
||||
are returned from C.
|
||||
</p>
|
||||
<p>
|
||||
The feature <i>intern_function</i> ensures that all C names are
|
||||
interned using the <b>swig-lispify</b> function. The "1" given
|
||||
to the feature is optional. The use of feature like
|
||||
<i>%feature("intern_function", "1");</i> globally enables
|
||||
interning for everything. If you want to target a single
|
||||
function, or declaration then use the targeted version of
|
||||
feature, <i>%feature("intern_function", "my-lispify")
|
||||
lispsort_double;</i>, here we are using an additional feature
|
||||
which allows us to use our lispify function.
|
||||
</p>
|
||||
<p>The <i>export</i> feature allows us to export the symbols. If
|
||||
the <i>package</i> argument is given, then the symbol will be exported to
|
||||
the specified Lisp package. The <i>inline</i> feature declaims the
|
||||
declared function as inline. The <i>rename</i> directive allows us to
|
||||
change the name(it is useful when generating C wrapper code for handling
|
||||
overloaded functions). The <i>ignore</i> directive ignores a certain
|
||||
declaration.
|
||||
</p>
|
||||
<p>There are several other things which are possible, to see some
|
||||
example of usage of SWIG look at the Lispbuilder and wxCL
|
||||
projects. The generated code with 'noswig-lisp' option is:
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
(cl:defconstant #.(swig-lispify "y" 'constant) 5)
|
||||
|
||||
(cl:export '#.(swig-lispify "y" 'constant))
|
||||
|
||||
(cl:defconstant #.(swig-lispify "x" 'constant) (cl:ash 5 -1))
|
||||
|
||||
(cl:export '#.(swig-lispify "x" 'constant))
|
||||
|
||||
(cffi:defcstruct #.(swig-lispify "bar" 'classname)
|
||||
(#.(swig-lispify "p" 'slotname) :short)
|
||||
(#.(swig-lispify "q" 'slotname) :short)
|
||||
(#.(swig-lispify "a" 'slotname) :char)
|
||||
(#.(swig-lispify "b" 'slotname) :char)
|
||||
(#.(swig-lispify "z" 'slotname) :pointer)
|
||||
(#.(swig-lispify "n" 'slotname) :pointer))
|
||||
|
||||
(cl:export '#.(swig-lispify "bar" 'classname))
|
||||
|
||||
(cl:export '#.(swig-lispify "p" 'slotname))
|
||||
|
||||
(cl:export '#.(swig-lispify "q" 'slotname))
|
||||
|
||||
(cl:export '#.(swig-lispify "a" 'slotname))
|
||||
|
||||
(cl:export '#.(swig-lispify "b" 'slotname))
|
||||
|
||||
(cl:export '#.(swig-lispify "z" 'slotname))
|
||||
|
||||
(cl:export '#.(swig-lispify "n" 'slotname))
|
||||
|
||||
(cffi:defcvar ("my_struct" #.(swig-lispify "my_struct" 'variable))
|
||||
:pointer)
|
||||
|
||||
(cl:export '#.(swig-lispify "my_struct" 'variable))
|
||||
|
||||
(cffi:defcstruct #.(swig-lispify "foo" 'classname)
|
||||
(#.(swig-lispify "a" 'slotname) :int)
|
||||
(#.(swig-lispify "b" 'slotname) :pointer))
|
||||
|
||||
(cl:export '#.(swig-lispify "foo" 'classname))
|
||||
|
||||
(cl:export '#.(swig-lispify "a" 'slotname))
|
||||
|
||||
(cl:export '#.(swig-lispify "b" 'slotname))
|
||||
|
||||
(cffi:defcfun ("renamed_cool_func" #.(swig-lispify "renamed_cool_func" 'function)) :int
|
||||
(p :my-pointer)
|
||||
(q :pointer)
|
||||
(r :pointer))
|
||||
|
||||
(cl:export '#.(swig-lispify "renamed_cool_func" 'function))
|
||||
|
||||
(cl:declaim (cl:inline #.(my-lispify "lispsort_double" 'function)))
|
||||
|
||||
(cffi:defcfun ("lispsort_double" #.(my-lispify "lispsort_double" 'function)) :void
|
||||
(n :int)
|
||||
(array :pointer))
|
||||
|
||||
(cl:export '#.(my-lispify "lispsort_double" 'function) 'some-other-package)
|
||||
|
||||
(cffi:defcenum #.(swig-lispify "color" 'enumname)
|
||||
#.(swig-lispify "RED" 'enumvalue :keyword)
|
||||
#.(swig-lispify "BLUE" 'enumvalue :keyword)
|
||||
#.(swig-lispify "GREEN" 'enumvalue :keyword))
|
||||
|
||||
(cl:export '#.(swig-lispify "color" 'enumname))
|
||||
|
||||
</pre></div>
|
||||
|
||||
<H3><a name="Lisp_nn6">29.2.3 Generating CFFI bindings for C++ code</a></H3>
|
||||
|
||||
|
||||
<p>This feature to SWIG (for CFFI) is very new and still far from
|
||||
complete. Pitch in with your patches, bug reports and feature
|
||||
requests to improve it.
|
||||
</p>
|
||||
<p> Generating bindings for C++ code, requires <i>-c++</i> option to be
|
||||
present and it first generates C binding which will wrap the C++
|
||||
code, and then generates the
|
||||
corresponding CFFI wrapper code. In the generated C wrapper
|
||||
code, you will often want to put your own C code, such as the
|
||||
code to include various files. This can be done by making use of
|
||||
"%{" and "%}" as shown below.
|
||||
</p>
|
||||
<div class="code"><pre>
|
||||
%{
|
||||
#include "Test/test.h"
|
||||
%}
|
||||
</pre></div>
|
||||
<p>
|
||||
Also, while parsing the C++ file and generating C wrapper code SWIG
|
||||
may need to be able to understand various symbols used in other
|
||||
header files. To help SWIG in doing this while ensuring that
|
||||
wrapper code is generated for the target file, use the "import"
|
||||
directive. The "include" directive specifies the target file for
|
||||
which wrapper code will be generated.
|
||||
</p>
|
||||
<div class="code"><pre>
|
||||
|
||||
%import "ancillary/header.h"
|
||||
|
||||
%include "target/header.h"
|
||||
|
||||
</pre></div>
|
||||
<p>
|
||||
Various features which were available for C headers can also be used
|
||||
here. The target header which we are going to use here is:
|
||||
</p>
|
||||
<div class="code"><pre>
|
||||
namespace OpenDemo {
|
||||
class Test
|
||||
{
|
||||
public:
|
||||
float x;
|
||||
// constructors
|
||||
Test (void) {x = 0;}
|
||||
Test (float X) {x = X;}
|
||||
|
||||
// vector addition
|
||||
Test operator+ (const Test& v) const {return Test (x+v.x);}
|
||||
|
||||
// length squared
|
||||
float lengthSquared (void) const {return this->dot (*this);}
|
||||
|
||||
static float distance (const Test& a, const Test& b){return(a-b).length();}
|
||||
|
||||
inline Test parallelComponent (const Test& unitBasis) const {
|
||||
return unitBasis * projection;
|
||||
}
|
||||
|
||||
Test setYtoZero (void) const {return Test (this->x);}
|
||||
|
||||
static const Test zero;
|
||||
};
|
||||
|
||||
inline Test operator* (float s, const Test& v) {return v*s;}
|
||||
|
||||
inline std::ostream& operator<< (std::ostream& o, const Test& v)
|
||||
{
|
||||
return o << "(" << v.x << ")";
|
||||
}
|
||||
|
||||
inline Test RandomUnitVectorOnXZPlane (void)
|
||||
{
|
||||
return RandomVectorInUnitRadiusSphere().setYtoZero().normalize();
|
||||
}
|
||||
}
|
||||
</pre></div>
|
||||
<p>The interface used is: </p>
|
||||
<div class="code"><pre>
|
||||
%module test
|
||||
%include "test.cpp"
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
SWIG generates 3 files, the first one is a C wrap which we don't show,
|
||||
the second is the plain CFFI wrapper which is as shown below:
|
||||
</p>
|
||||
<div class="targetlang"><pre>
|
||||
(cffi:defcfun ("_wrap_Test_x_set" Test_x_set) :void
|
||||
(self :pointer)
|
||||
(x :float))
|
||||
|
||||
(cffi:defcfun ("_wrap_Test_x_get" Test_x_get) :float
|
||||
(self :pointer))
|
||||
|
||||
(cffi:defcfun ("_wrap_new_Test__SWIG_0" new_Test) :pointer)
|
||||
|
||||
(cffi:defcfun ("_wrap_new_Test__SWIG_1" new_Test) :pointer
|
||||
(X :float))
|
||||
|
||||
(cffi:defcfun ("_wrap_Test___add__" Test___add__) :pointer
|
||||
(self :pointer)
|
||||
(v :pointer))
|
||||
|
||||
(cffi:defcfun ("_wrap_Test_lengthSquared" Test_lengthSquared) :float
|
||||
(self :pointer))
|
||||
|
||||
(cffi:defcfun ("_wrap_Test_distance" Test_distance) :float
|
||||
(a :pointer)
|
||||
(b :pointer))
|
||||
|
||||
(cffi:defcfun ("_wrap_Test_parallelComponent" Test_parallelComponent) :pointer
|
||||
(self :pointer)
|
||||
(unitBasis :pointer))
|
||||
|
||||
(cffi:defcfun ("_wrap_Test_setYtoZero" Test_setYtoZero) :pointer
|
||||
(self :pointer))
|
||||
|
||||
(cffi:defcvar ("Test_zero" Test_zero)
|
||||
:pointer)
|
||||
|
||||
(cffi:defcfun ("_wrap_delete_Test" delete_Test) :void
|
||||
(self :pointer))
|
||||
|
||||
(cffi:defcfun ("_wrap___mul__" __mul__) :pointer
|
||||
(s :float)
|
||||
(v :pointer))
|
||||
|
||||
(cffi:defcfun ("_wrap___lshift__" __lshift__) :pointer
|
||||
(o :pointer)
|
||||
(v :pointer))
|
||||
|
||||
(cffi:defcfun ("_wrap_RandomUnitVectorOnXZPlane" RandomUnitVectorOnXZPlane) :pointer)
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
The output is pretty good but it fails in disambiguating overloaded
|
||||
functions such as the constructor, in this case. One way of
|
||||
resolving this problem is to make the interface use the rename
|
||||
directiv, but hopefully there are better solutions.
|
||||
In addition SWIG also generates, a CLOS file
|
||||
</p>
|
||||
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
(clos:defclass test()
|
||||
((ff :reader ff-pointer)))
|
||||
|
||||
(clos:defmethod (cl:setf x) (arg0 (obj test))
|
||||
(Test_x_set (ff-pointer obj) arg0))
|
||||
|
||||
(clos:defmethod x ((obj test))
|
||||
(Test_x_get (ff-pointer obj)))
|
||||
|
||||
(cl:shadow "+")
|
||||
(clos:defmethod + ((obj test) (self test) (v test))
|
||||
(Test___add__ (ff-pointer obj) (ff-pointer self) (ff-pointer v)))
|
||||
|
||||
(clos:defmethod length-squared ((obj test) (self test))
|
||||
(Test_lengthSquared (ff-pointer obj) (ff-pointer self)))
|
||||
|
||||
(clos:defmethod parallel-component ((obj test) (self test) (unitBasis test))
|
||||
(Test_parallelComponent (ff-pointer obj) (ff-pointer self) (ff-pointer unitBasis)))
|
||||
|
||||
(clos:defmethod set-yto-zero ((obj test) (self test))
|
||||
(Test_setYtoZero (ff-pointer obj) (ff-pointer self)))
|
||||
</pre></div>
|
||||
|
||||
<p>I agree that the CFFI C++ module needs lot more work. But I hope it
|
||||
provides a starting point, on which you can base your work of
|
||||
importing C++ libraries to Lisp.
|
||||
</p>
|
||||
<p>
|
||||
If you have any questions, suggestions, patches, etc., related to CFFI
|
||||
module feel free to contact us on the SWIG mailing list, and
|
||||
also please add a "[CFFI]" tag in the subject line.
|
||||
|
||||
<H3><a name="Lisp_nn7">29.2.4 Inserting user code into generated files</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
It is often necessary to <a href="SWIG.html#SWIG_nn40">include user-defined code</a>
|
||||
into the automatically generated interface files. For example, when building
|
||||
a C++ interface, example_wrap.cxx will likely not compile unless
|
||||
you add a <tt>#include "header.h"</tt> directive. This can be done
|
||||
using the SWIG <tt>%insert(section) %{ ...code... %}</tt> directive:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%module example
|
||||
|
||||
%{
|
||||
#include "header.h"
|
||||
%}
|
||||
|
||||
%include "header.h"
|
||||
|
||||
int fact(int n);
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Additional sections have been added for inserting into the
|
||||
generated lisp interface file:
|
||||
</p>
|
||||
<ul>
|
||||
<li><tt>lisphead</tt> - inserts before type declarations</li>
|
||||
<li><tt>swiglisp</tt> - inserts after type declarations according to
|
||||
where it appears in the .i file</li>
|
||||
</ul>
|
||||
<p>
|
||||
Note that the block <tt>%{ ... %}</tt> is effectively a shortcut for
|
||||
<tt>%insert("header") %{ ... %}</tt>.
|
||||
</p>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,97 @@
|
|||
# Makefile for generating the SWIG documentation
|
||||
#
|
||||
# Note that the htmldoc package needs to be installed. wkhtmltopdf patched with qt is also required
|
||||
# and can be installed from http://wkhtmltopdf.org/downloads.html.
|
||||
#
|
||||
# The .html files are first processed and updated with chapter numbering and anchor names
|
||||
# are added to the HTML headings using the python scripts. The htmldoc program is then
|
||||
# used to generate the single page HTML version of the documentation.
|
||||
# wkhtmltopdf is used to generate the pdf document from the single page html file.
|
||||
# HTML TIDY (package also known as tidy) is also required and is used as an aid to HTML
|
||||
# validation.
|
||||
#
|
||||
# Additional html validation can be done using the validate target.
|
||||
# Additional link checking can be done using the linkchecker1 and linkchecker2 target.
|
||||
#
|
||||
|
||||
# Note the # and " are escaped
|
||||
HTMLDOC_OPTIONS = "--book --toclevels 4 --no-numbered --toctitle \"Table of Contents\" --title --titleimage swig16.png --linkcolor \#0000ff --linkstyle underline --size Universal --left 0.50in --right 0.50in --top 0.50in --bottom 0.50in --header .t. --footer h.1 --nup 1 --tocheader .t. --tocfooter ..i --portrait --color --no-pscommands --no-xrxcomments --compression=1 --jpeg=0 --fontsize 10.0 --fontspacing 1.2 --headingfont Helvetica --bodyfont Times --headfootsize 10.0 --headfootfont Helvetica --charset iso-8859-1 --links --no-embedfonts --pagemode outline --pagelayout single --firstpage c1 --pageeffect none --pageduration 10 --effectduration 1.0 --no-encryption --permissions all --owner-password \"\" --user-password \"\" --browserwidth 680"
|
||||
|
||||
.PHONY: maketoc check generate all maintainer-clean validate test
|
||||
|
||||
all: maketoc check generate
|
||||
|
||||
maketoc:
|
||||
python maketoc.py
|
||||
|
||||
# Use this to regenerate CCache.html should this ever be needed
|
||||
CCache.html: ../../CCache/ccache.yo
|
||||
yodl2html -o CCache.html ../../CCache/ccache.yo
|
||||
|
||||
# Tabs in the html files will stop the build as wkhtmltopdf does not expand them correctly - replace them with the appropriate number of tabs
|
||||
# Use htmltidy to warn about some HTML errors. Note that it is not used to clean/tidy the HTML,
|
||||
# it is just used as a primitive HTML checker.
|
||||
# CCache.html is generated by yodl2html and has a few insignificant problems, so we don't put it through tidy
|
||||
check:
|
||||
all="index.html Sections.html `sed '/^#/d' chapters | grep -v CCache.html`" && for a in $$all; do echo "Check for tabs $$a" && if grep -P '\t' $$a; then echo "Please delete the tabs from the lines above" && exit 1; fi; done && for a in $$all; do echo "HTML tidy check $$a" && tidy -errors --gnu-emacs yes -quiet $$a; done;
|
||||
|
||||
# Note wkhtmltopdf limitations for generating pdf docs:
|
||||
# 1) <H1><a name="X"></a>Text</H1> style links don't work and need changing to
|
||||
# <H1><a name="X">Text</a></H1>
|
||||
# 2) Tabs in <pre> elements should be expanded to 8 spaces by default, but
|
||||
# are expanded to just one space and css tab-size is not working.
|
||||
# 3) <pre> <tt> <code> elements do not always select a fixed-width font - try installing the
|
||||
# Courier font to fix - these have been added to style.css.
|
||||
generate: SWIGDocumentation.html
|
||||
wkhtmltopdf --version | grep "with patched qt" || (echo "wkhtmltopdf is not the patched qt version and so cannot be used - download it from http://wkhtmltopdf.org/downloads.html" && false)
|
||||
wkhtmltopdf --margin-top 20mm --margin-bottom 20mm --margin-left 10mm --margin-right 10mm --header-font-size 6 --footer-font-size 6 --header-spacing 6 --footer-spacing 6 --header-center '[doctitle]' --footer-left '[subsection]' --footer-right '[page]' SWIGDocumentation.html SWIGDocumentation.pdf
|
||||
|
||||
SWIGDocumentation.html: swightml.book
|
||||
htmldoc --batch swightml.book || true
|
||||
python fixstyle.py SWIGDocumentation.html
|
||||
|
||||
swightml.book: chapters Sections.html
|
||||
echo "#HTMLDOC 1.8.24" > swightml.book
|
||||
echo -t html -f SWIGDocumentation.html $(HTMLDOC_OPTIONS) >> swightml.book
|
||||
echo "Sections.html" >> swightml.book
|
||||
cat chapters >> swightml.book
|
||||
|
||||
maintainer-clean: clean-baks
|
||||
rm -f swightml.book
|
||||
rm -f SWIGDocumentation.html
|
||||
rm -f SWIGDocumentation.pdf
|
||||
rm -rf linkchecker-tmp
|
||||
|
||||
clean-baks:
|
||||
rm -f *.bak
|
||||
|
||||
test:
|
||||
grep "href=\".*\.html\"" index.html
|
||||
grep "href=\".*\.html\"" Sections.html
|
||||
all=`sed '/^#/d' chapters`; for a in $$all; do grep -l "href=\".*\.html\"" $$a; done;
|
||||
|
||||
# Validating using the WDG offline validator - http://www.htmlhelp.com/tools/validator/offline/
|
||||
validate:
|
||||
all=`sed '/^#/d' chapters`; for a in $$all; do validate --emacs $$a; done;
|
||||
|
||||
# Link checking using linkchecker of the index.html only file (including anchors)
|
||||
linkchecker1:
|
||||
@echo -----------------------------------------------------------------------
|
||||
@echo Note linkchecker versions prior to 6.1 do not work properly wrt anchors
|
||||
@echo -----------------------------------------------------------------------
|
||||
linkchecker --config=./linkchecker.config --anchors index.html
|
||||
|
||||
# Check for links which don't work including those generated from the individual .html files into SWIGDocumentation.html
|
||||
linkchecker2:
|
||||
rm -rf linkchecker-tmp
|
||||
mkdir linkchecker-tmp
|
||||
cp SWIGDocumentation.html linkchecker-tmp
|
||||
cp *.png linkchecker-tmp
|
||||
(cd linkchecker-tmp && linkchecker --config=../linkchecker.config -F text --no-warnings SWIGDocumentation.html)
|
||||
|
||||
# Simple check for relative links (there shouldn't be any), they don't translate properly creating the .pdf doc
|
||||
# with wkhtmltopdf. For example, href="SWIG.html" needs to be href="SWIG.html#SWIG"
|
||||
linkchecker3:
|
||||
@echo "The following list should just contain SWIGDocumentation.html and SWIGDocumentation.pdf,"
|
||||
@echo "as all links should have an anchor (with a #) or be a full url beginning http."
|
||||
grep 'href="' *.html | sed -e 's/.*href="\(.*\)">.*$$/\1/' | grep -v "#" | grep -v "^http" | grep -v "^style.css"
|
|
@ -0,0 +1,942 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and Modula-3</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF">
|
||||
<H1><a name="Modula3">31 SWIG and Modula-3</a></H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#Modula3_modula3_overview">Overview</a>
|
||||
<ul>
|
||||
<li><a href="#Modula3_motivation">Motivation</a>
|
||||
</ul>
|
||||
<li><a href="#Modula3_conception">Conception</a>
|
||||
<ul>
|
||||
<li><a href="#Modula3_cinterface">Interfaces to C libraries</a>
|
||||
<li><a href="#Modula3_cppinterface">Interfaces to C++ libraries</a>
|
||||
</ul>
|
||||
<li><a href="#Modula3_preliminaries">Preliminaries</a>
|
||||
<ul>
|
||||
<li><a href="#Modula3_compilers">Compilers</a>
|
||||
<li><a href="#Modula3_commandline">Additional Commandline Options</a>
|
||||
</ul>
|
||||
<li><a href="#Modula3_typemaps">Modula-3 typemaps</a>
|
||||
<ul>
|
||||
<li><a href="#Modula3_inoutparam">Inputs and outputs</a>
|
||||
<li><a href="#Modula3_ordinals">Subranges, Enumerations, Sets</a>
|
||||
<li><a href="#Modula3_class">Objects</a>
|
||||
<li><a href="#Modula3_imports">Imports</a>
|
||||
<li><a href="#Modula3_exceptions">Exceptions</a>
|
||||
<li><a href="#Modula3_typemap_example">Example</a>
|
||||
</ul>
|
||||
<li><a href="#Modula3_hints">More hints to the generator</a>
|
||||
<ul>
|
||||
<li><a href="#Modula3_features">Features</a>
|
||||
<li><a href="#Modula3_pragmas">Pragmas</a>
|
||||
</ul>
|
||||
<li><a href="#Modula3_remarks">Remarks</a>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
This chapter describes SWIG's support for
|
||||
<a href="http://modula3.org/">Modula-3</a>.
|
||||
You should be familiar with the
|
||||
<a href="SWIG.html#SWIG">basics</a>
|
||||
of SWIG,
|
||||
especially
|
||||
<a href="Typemaps.html#Typemaps">typemaps</a>.
|
||||
</p>
|
||||
|
||||
<H2><a name="Modula3_modula3_overview">31.1 Overview</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
Modula-3 is a compiled language in the tradition of Niklaus Wirth's Modula 2,
|
||||
which is in turn a successor to Pascal.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
SWIG's Modula-3 support is currently very basic and highly experimental!
|
||||
Many features are still not designed satisfyingly
|
||||
and I need more discussion about the odds and ends.
|
||||
Don't rely on any feature, incompatible changes are likely in the future!
|
||||
However, the Modula-3 generator was already useful for interfacing
|
||||
to the libraries:
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li>
|
||||
<a href="http://www.elegosoft.com/cgi-bin/cvsweb.cgi/cm3/m3-libs/plplot/">
|
||||
PLPlot
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://www.elegosoft.com/cgi-bin/cvsweb.cgi/cm3/m3-libs/fftw/">
|
||||
FFTW
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<H3><a name="Modula3_motivation">31.1.1 Motivation</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Although it is possible to write Modula-3 code that performs as well as C/C++
|
||||
most existing libraries are not written in Modula-3 but in C or C++, and
|
||||
even libraries in other languages may provide C header files.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Fortunately Modula-3 can call C functions, but you have to write Modula-3
|
||||
interfaces to them, and to make things comfortable you will also need
|
||||
wrappers that convert between high-level features of Modula-3 (garbage
|
||||
collecting, exceptions) and the explicit tracking of allocated memory and
|
||||
exception codes used by C APIs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
SWIG converts C headers to Modula-3 interfaces for you, and using typemaps
|
||||
you can pass <tt>TEXT</tt>s or open arrays, and convert error return codes
|
||||
into exceptions.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If the library API is ill designed
|
||||
writing appropriate typemaps can still be time-consuming.
|
||||
E.g. C programmers are very creative to work-around
|
||||
missing data types like (real) enumerations and sets.
|
||||
You should turn such work-arounds back to the Modula-3 way
|
||||
otherwise you lose static safety and consistency.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Without SWIG you would probably never consider trying to call C++ libraries
|
||||
from Modula-3, but with SWIG this is becomes feasible.
|
||||
SWIG can generate C wrappers to C++ functions and object methods
|
||||
that may throw exceptions, and then wrap these C wrappers for Modula-3.
|
||||
To make it complete you can then hide the C interface with Modula-3 classes and
|
||||
exceptions.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
SWIG allows you to call C and C++ libraries from Modula-3 (even with call back
|
||||
functions), but it doesn't allow you to easily integrate a Modula-3 module into
|
||||
a C/C++ project.
|
||||
</p>
|
||||
|
||||
<H2><a name="Modula3_conception">31.2 Conception</a></H2>
|
||||
|
||||
|
||||
<H3><a name="Modula3_cinterface">31.2.1 Interfaces to C libraries</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Modula-3 has integrated support for calling C functions.
|
||||
This is also extensively used by the standard Modula-3 libraries
|
||||
to call OS functions.
|
||||
The Modula-3 part of SWIG and the corresponding SWIG library
|
||||
modula3.swg
|
||||
contain code that uses these features.
|
||||
Because of the built-in support there is no need
|
||||
for calling the SWIG kernel to generate wrappers written in C.
|
||||
All conversion and argument checking can be done in Modula-3
|
||||
and the interfacing is quite efficient.
|
||||
All you have to do is to write pieces of Modula-3 code
|
||||
that SWIG puts together.
|
||||
</p>
|
||||
|
||||
<table border summary="Modula-3 C library support">
|
||||
<tr><th colspan=2>C library support integrated in Modula-3<th></tr>
|
||||
<tr>
|
||||
<td>Pragma <tt><* EXTERNAL *></tt></td>
|
||||
<td>Precedes a declaration of a PROCEDURE that is implemented
|
||||
in an external library instead of a Modula-3 module.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pragma <tt><* CALLBACK *></tt></td>
|
||||
<td>Precedes a declaration of a PROCEDURE that should be called
|
||||
by external library code.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Module <tt>Ctypes</tt></td>
|
||||
<td>Contains Modula-3 types that match some basic C types.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Module <tt>M3toC</tt></td>
|
||||
<td>Contains routines that convert between Modula-3's <tt>TEXT</tt> type
|
||||
and C's <tt>char *</tt> type.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
In each run of SWIG the Modula-3 part
|
||||
generates several files:
|
||||
</p>
|
||||
<table border summary="Modula-3 generated files">
|
||||
<tr>
|
||||
<th>Module name scheme</th>
|
||||
<th>Identifier for <tt>%insert</tt></th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Module<tt>Raw.i3</tt></td>
|
||||
<td><tt>m3rawintf</tt></td>
|
||||
<td>Declaration of types that are equivalent to those of the C library,
|
||||
<tt>EXTERNAL</tt> procedures as interface to the C library functions</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Module<tt>Raw.m3</tt></td>
|
||||
<td><tt>m3rawimpl</tt></td>
|
||||
<td>Almost empty.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Module<tt>.i3</tt></td>
|
||||
<td><tt>m3wrapintf</tt></td>
|
||||
<td>Declaration of comfortable wrappers to the C library functions.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Module<tt>.m3</tt></td>
|
||||
<td><tt>m3wrapimpl</tt></td>
|
||||
<td>Implementation of the wrappers that
|
||||
convert between Modula-3 and C types,
|
||||
check for validity of values,
|
||||
hand-over resource management to the garbage collector using <tt>WeakRef</tt>s
|
||||
and raises exceptions.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>m3makefile</tt></td>
|
||||
<td><tt>m3makefile</tt></td>
|
||||
<td>Add the modules above to the Modula-3 project and
|
||||
specify the name of the Modula-3 wrapper library
|
||||
to be generated.
|
||||
|
||||
Today I'm not sure if it is a good idea
|
||||
to create a <tt>m3makefile</tt> in each run,
|
||||
because SWIG must be started for each Modula-3 module it creates.
|
||||
Thus the m3makefile is overwritten each time. :-(
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
Here's a scheme of how the function calls to Modula-3 wrappers
|
||||
are redirected to C library functions:
|
||||
</p>
|
||||
|
||||
<table summary="Modula-3 C library">
|
||||
<tr>
|
||||
<td align=center>
|
||||
Modula-3 wrapper<br>
|
||||
Module<tt>.i3</tt><br>
|
||||
generated by Modula-3 part of SWIG
|
||||
</td>
|
||||
<td></td>
|
||||
<td align=center></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align=center>
|
||||
<!-- pre tag overrides centering -->
|
||||
|<br>
|
||||
v
|
||||
</td>
|
||||
<td></td>
|
||||
<td align=center></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align=center>
|
||||
Modula-3 interface to C<br>
|
||||
Module<tt>Raw.i3</tt><br>
|
||||
generated by Modula-3 part of SWIG
|
||||
</td>
|
||||
<td>--></td>
|
||||
<td align=center>
|
||||
C library
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<p>
|
||||
I have still no good conception how one can split C library interfaces
|
||||
into type oriented interfaces.
|
||||
A Module in Modula-3 represents an Abstract DataType
|
||||
(or call it a static classes, i.e. a class without virtual methods).
|
||||
E.g. if you have a principal type, say <tt>Database</tt>,
|
||||
it is good Modula-3 style to set up one Module with the name <tt>Database</tt>
|
||||
where the database type is declared with the name <tt>T</tt>
|
||||
and where all functions are declared that operates on it.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The normal operation of SWIG is to generate a fixed set of files per call.
|
||||
To generate multiple modules one has to write one SWIG interface
|
||||
(different SWIG interfaces can share common data) per module.
|
||||
Identifiers belonging to a different module may ignored (<tt>%ignore</tt>)
|
||||
and the principal type must be renamed (<tt>%typemap</tt>).
|
||||
</p>
|
||||
|
||||
|
||||
<H3><a name="Modula3_cppinterface">31.2.2 Interfaces to C++ libraries</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Interfaces to C++ files are much more complicated and
|
||||
there are some more design decisions that are not made, yet.
|
||||
Modula-3 has no support for C++ functions
|
||||
but C++ compilers should support generating C++ functions
|
||||
with a C interface.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Here's a scheme of how the function calls to Modula-3 wrappers
|
||||
are redirected to C library functions:
|
||||
</p>
|
||||
|
||||
<table summary="Modula-3 C++ library">
|
||||
<tr>
|
||||
<td align=center>
|
||||
Modula-3 wrapper<br>
|
||||
Module<tt>.i3</tt><br>
|
||||
generated by Modula-3 part of SWIG
|
||||
</td>
|
||||
<td></td>
|
||||
<td align=center>C++ library</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align=center>
|
||||
<!-- pre tag overrides centering -->
|
||||
|<br>
|
||||
v
|
||||
</td>
|
||||
<td></td>
|
||||
<td align=center>
|
||||
^<br>
|
||||
|
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align=center>
|
||||
Modula-3 interface to C<br>
|
||||
Module<tt>Raw.i3</tt><br>
|
||||
generated by Modula-3 part of SWIG
|
||||
</td>
|
||||
<td>--></td>
|
||||
<td align=center>
|
||||
C interface to C++<br>
|
||||
module<tt>_wrap.cxx</tt><br>
|
||||
generated by the SWIG core
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
Wrapping C++ libraries arises additional problems:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
Is it sensible to wrap C++ classes with Modula-3 classes?
|
||||
</li>
|
||||
<li>
|
||||
How to find the wrapping Modula-3 class
|
||||
for a class pointer that is returned by a C++ routine?
|
||||
</li>
|
||||
<li>
|
||||
How to deal with multiple inheritance
|
||||
which was neglected for Modula-3 for good reasons?
|
||||
</li>
|
||||
<li>
|
||||
Is it possible to sub-class C++ classes with Modula-3 code?
|
||||
This issue is addressed by directors,
|
||||
a feature that was experimentally added to some Language modules
|
||||
like
|
||||
<a href="Java.html#Java_directors">Java</a> and
|
||||
<a href="Python.html#Python_directors">Python</a>.
|
||||
</li>
|
||||
<li>
|
||||
How to manage storage with the garbage collector of Modula-3?
|
||||
Support for
|
||||
<a href="Customization.html#Customization_ownership">
|
||||
<tt>%newobject</tt> and <tt>%typemap(newfree)</tt></a>
|
||||
isn't implemented, yet.
|
||||
What's about resources that are managed by the garbage collector
|
||||
but shall be passed back to the storage management of the C++ library?
|
||||
This is a general issue which is not solved in a satisfying fashion
|
||||
as far as I know.
|
||||
</li>
|
||||
<li>
|
||||
How to turn C++ exceptions into Modula-3 exceptions?
|
||||
There's also no support for
|
||||
<a href="Customization.html#Customization_exception">
|
||||
<tt>%exception</tt></a>, yet.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Be warned:
|
||||
There is no C++ library I wrote a SWIG interface for,
|
||||
so I'm not sure if this is possible or sensible, yet.
|
||||
</p>
|
||||
|
||||
<H2><a name="Modula3_preliminaries">31.3 Preliminaries</a></H2>
|
||||
|
||||
|
||||
<H3><a name="Modula3_compilers">31.3.1 Compilers</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
There are different Modula-3 compilers around:
|
||||
cm3, pm3, ezm3, Klagenfurth Modula-3, Cambridge Modula-3.
|
||||
SWIG itself does not contain compiler specific code
|
||||
but the modula3.swg library file
|
||||
may do so.
|
||||
For testing examples I use Critical Mass cm3.
|
||||
</p>
|
||||
|
||||
|
||||
<H3><a name="Modula3_commandline">31.3.2 Additional Commandline Options</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
There are some experimental command line options
|
||||
that prevent SWIG from generating interface files.
|
||||
Instead files are emitted that may assist you
|
||||
when writing SWIG interface files.
|
||||
</p>
|
||||
|
||||
<table border summary="Modula-3 specific options">
|
||||
<tr>
|
||||
<th>Modula-3 specific options</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign=top>-generateconst <file></td>
|
||||
<td>
|
||||
Disable generation of interfaces and wrappers.
|
||||
Instead write code for computing numeric values of constants
|
||||
to the specified file.
|
||||
<br>
|
||||
C code may contain several constant definitions
|
||||
written as preprocessor macros.
|
||||
Other language modules of SWIG use
|
||||
compute-once-use-readonly variables or
|
||||
functions to wrap such definitions.
|
||||
All of them can invoke C code dynamically
|
||||
for computing the macro values.
|
||||
But if one wants to turn them into Modula-3
|
||||
integer constants, enumerations or set types,
|
||||
the values of these expressions has to be known statically.
|
||||
Although definitions like <tt>(1 << FLAG_MAXIMIZEWINDOW)</tt>
|
||||
must be considered as good C style
|
||||
they are hard to convert to Modula-3
|
||||
since the value computation can use every feature of C.
|
||||
<br>
|
||||
Thus I implemented these switch
|
||||
to extract all constant definitions
|
||||
and write a C program that output the values of them.
|
||||
It works for numeric constants only
|
||||
and treats all of them as <tt>double</tt>.
|
||||
Future versions may generate a C++ program
|
||||
that can detect the type of the macros
|
||||
by overloaded output functions.
|
||||
Then strings can also be processed.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign=top>-generaterename <file></td>
|
||||
<td>
|
||||
Disable generation of interfaces and wrappers.
|
||||
Instead generate suggestions for <tt>%rename</tt>.
|
||||
<br>
|
||||
C libraries use a naming style
|
||||
that is neither homogeneous nor similar to that of Modula-3.
|
||||
C function names often contain a prefix denoting the library
|
||||
and some name components separated by underscores
|
||||
or capitalization changes.
|
||||
To get library interfaces that are really Modula-3 like
|
||||
you should rename the function names with the <tt>%rename</tt> directive.
|
||||
This switch outputs a list of such directives
|
||||
with a name suggestion generated by a simple heuristic.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign=top>-generatetypemap <file></td>
|
||||
<td>
|
||||
Disable generation of interfaces and wrappers.
|
||||
Instead generate templates for some basic typemaps.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<H2><a name="Modula3_typemaps">31.4 Modula-3 typemaps</a></H2>
|
||||
|
||||
|
||||
<H3><a name="Modula3_inoutparam">31.4.1 Inputs and outputs</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Each C procedure has a bunch of inputs and outputs.
|
||||
Inputs are passed as function arguments,
|
||||
outputs are updated referential arguments and
|
||||
the function value.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Each C type can have several typemaps
|
||||
that apply only in case if a type is used
|
||||
for an input argument, for an output argument,
|
||||
or for a return value.
|
||||
A further typemap may specify
|
||||
the direction that is used for certain parameters.
|
||||
I have chosen this separation
|
||||
in order to be able to write general typemaps for the modula3.swg typemap library.
|
||||
In the library code the final usage of the type is not known.
|
||||
Using separate typemaps for each possible use
|
||||
allows appropriate definitions for each case.
|
||||
If these pre-definitions are fine
|
||||
then the direction of the function parameter
|
||||
is the only hint the user must give.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The typemaps specific to Modula-3 have a common name scheme:
|
||||
A typemap name starts with "m3",
|
||||
followed by "raw" or "wrap"
|
||||
depending on whether it controls the generation
|
||||
of the Module<tt>Raw.i3</tt> or the Module<tt>.i3</tt>, respectively.
|
||||
It follows an "in" for typemaps applied to input argument,
|
||||
"out" for output arguments, "arg" for all kind of arguments,
|
||||
"ret" for returned values.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The main task of SWIG is to build wrapper function,
|
||||
i.e. functions that convert values between C and Modula-3
|
||||
and call the corresponding C function.
|
||||
Modula-3 wrapper functions generated by SWIG
|
||||
consist of the following parts:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Generate <tt>PROCEDURE</tt> signature.</li>
|
||||
<li>Declare local variables.</li>
|
||||
<li>Convert input values from Modula-3 to C.</li>
|
||||
<li>Check for input value integrity.</li>
|
||||
<li>Call the C function.</li>
|
||||
<li>Check returned values, e.g. error codes.</li>
|
||||
<li>Convert and write back values into Modula-3 records.</li>
|
||||
<li>Free temporary storage.</li>
|
||||
<li>Return values.</li>
|
||||
</ul>
|
||||
|
||||
<table border summary="Modula-3 typemaps">
|
||||
<tr>
|
||||
<th>Typemap</th>
|
||||
<th>Example</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapargvar</td>
|
||||
<td><tt>$1: INTEGER := $1_name;</tt></td>
|
||||
<td>
|
||||
Declaration of some variables needed for temporary results.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapargconst</td>
|
||||
<td><tt>$1 = "$1_name";</tt></td>
|
||||
<td>
|
||||
Declaration of some constant, maybe for debug purposes.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapargraw</td>
|
||||
<td><tt>ORD($1_name)</tt></td>
|
||||
<td>
|
||||
The expression that should be passed as argument to the raw Modula-3 interface function.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapargdir</td>
|
||||
<td><tt>out</tt></td>
|
||||
<td>
|
||||
Referential arguments can be used for input, output, update.
|
||||
???
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapinmode</td>
|
||||
<td><tt>READONLY</tt></td>
|
||||
<td>
|
||||
One of Modula-3 parameter modes
|
||||
<tt>VALUE</tt> (or empty),
|
||||
<tt>VAR</tt>,
|
||||
<tt>READONLY</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapinname</td>
|
||||
<td></td>
|
||||
<td>
|
||||
New name of the input argument.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapintype</td>
|
||||
<td></td>
|
||||
<td>
|
||||
Modula-3 type of the input argument.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapindefault</td>
|
||||
<td></td>
|
||||
<td>
|
||||
Default value of the input argument
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapinconv</td>
|
||||
<td><tt>$1 := M3toC.SharedTtoS($1_name);</tt></td>
|
||||
<td>
|
||||
Statement for converting the Modula-3 input value to C compliant value.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapincheck</td>
|
||||
<td><tt>IF Text.Length($1_name) > 10 THEN RAISE E("str too long"); END;</tt></td>
|
||||
<td>
|
||||
Check the integrity of the input value.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapoutname</td>
|
||||
<td></td>
|
||||
<td>
|
||||
Name of the <tt>RECORD</tt> field to be used for returning multiple values.
|
||||
This applies to referential output arguments that shall be turned
|
||||
into return values.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapouttype</td>
|
||||
<td></td>
|
||||
<td>
|
||||
Type of the value that is returned instead of a referential output argument.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapoutconv</td>
|
||||
<td></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapoutcheck</td>
|
||||
<td></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapretraw</td>
|
||||
<td></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapretname</td>
|
||||
<td></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wraprettype</td>
|
||||
<td></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapretvar</td>
|
||||
<td></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapretconv</td>
|
||||
<td></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapretcheck</td>
|
||||
<td></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>m3wrapfreearg</td>
|
||||
<td><tt>M3toC.FreeSharedS(str, arg1);</tt></td>
|
||||
<td>
|
||||
Free resources that were temporarily used in the wrapper.
|
||||
Since this step should never be skipped,
|
||||
SWIG will put it in the <tt>FINALLY</tt> branch
|
||||
of a <tt>TRY .. FINALLY</tt> structure.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<H3><a name="Modula3_ordinals">31.4.2 Subranges, Enumerations, Sets</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Subranges, enumerations, and sets are machine oriented types
|
||||
that make Modula very strong and expressive compared
|
||||
with the type systems of many other languages.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Subranges are used for statically restricted choices of integers.
|
||||
</li>
|
||||
<li>
|
||||
Enumerations are used for named choices.
|
||||
</li>
|
||||
<li>
|
||||
Sets are commonly used for flag (option) sets.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Using them extensively makes Modula code very safe and readable.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
C supports enumerations, too, but they are not as safe as the ones of Modula.
|
||||
Thus they are abused for many things:
|
||||
For named choices, for integer constant definitions, for sets.
|
||||
To make it complete every way of defining a value in C
|
||||
(<tt>#define</tt>, <tt>const int</tt>, <tt>enum</tt>)
|
||||
is somewhere used for defining something
|
||||
that must be handled completely different in Modula-3
|
||||
(<tt>INTEGER</tt>, enumeration, <tt>SET</tt>).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
I played around with several <tt>%feature</tt>s and <tt>%pragma</tt>s
|
||||
that split the task up into converting
|
||||
the C bit patterns (integer or bit set)
|
||||
into Modula-3 bit patterns (integer or bit set)
|
||||
and change the type as requested.
|
||||
See the corresponding example in the
|
||||
Examples/modula3/enum/example.i file.
|
||||
This is quite messy and not satisfying.
|
||||
So the best what you can currently do is
|
||||
to rewrite constant definitions manually.
|
||||
Though this is a tedious work
|
||||
that I'd like to automate.
|
||||
</p>
|
||||
|
||||
|
||||
<H3><a name="Modula3_class">31.4.3 Objects</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Declarations of C++ classes are mapped to <tt>OBJECT</tt> types
|
||||
while it is tried to retain the access hierarchy
|
||||
"public - protected - private" using partial revelation.
|
||||
Though the example in
|
||||
Examples/modula3/class/example.i
|
||||
is not really useful, yet.
|
||||
</p>
|
||||
|
||||
|
||||
<H3><a name="Modula3_imports">31.4.4 Imports</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Pieces of Modula-3 code provided by typemaps
|
||||
may contain identifiers from foreign modules.
|
||||
If the typemap <tt>m3wrapinconv</tt> for <tt>blah *</tt>
|
||||
contains code using the function <tt>M3toC.SharedTtoS</tt>
|
||||
you may declare <tt>%typemap("m3wrapinconv:import") blah * %{M3toC%}</tt>.
|
||||
Then the module <tt>M3toC</tt> is imported
|
||||
if the <tt>m3wrapinconv</tt> typemap for <tt>blah *</tt>
|
||||
is used at least once.
|
||||
Use <tt>%typemap("m3wrapinconv:import") blah * %{MyConversions AS M3toC%}</tt>
|
||||
if you need module renaming.
|
||||
Unqualified import is not supported.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It is cumbersome to add this typemap to each piece of Modula-3 code.
|
||||
It is especially useful when writing general typemaps
|
||||
for the modula3.swg typemap library.
|
||||
For a monolithic module you might be better off
|
||||
if you add the imports directly:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%insert(m3rawintf) %{
|
||||
IMPORT M3toC;
|
||||
%}
|
||||
</pre></div>
|
||||
|
||||
|
||||
<H3><a name="Modula3_exceptions">31.4.5 Exceptions</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Modula-3 provides another possibility
|
||||
of an output of a function: exceptions.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Any piece of Modula-3 code that SWIG inserts
|
||||
due to a typemap can raise an exception.
|
||||
This way you can also convert an error code
|
||||
from a C function into a Modula-3 exception.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <tt>RAISES</tt> clause is controlled
|
||||
by typemaps with the <tt>throws</tt> extension.
|
||||
If the typemap <tt>m3wrapinconv</tt> for <tt>blah *</tt>
|
||||
contains code that may raise the exceptions <tt>OSError.E</tt>
|
||||
you should declare
|
||||
<tt>%typemap("m3wrapinconv:throws") blah * %{OSError.E%}</tt>.
|
||||
</p>
|
||||
|
||||
<H3><a name="Modula3_typemap_example">31.4.6 Example</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
The generation of wrappers in Modula-3 needs very fine control
|
||||
to take advantage of the language features.
|
||||
Here is an example of a generated wrapper
|
||||
where almost everything is generated by a typemap:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
<I> (* %relabel m3wrapinmode m3wrapinname m3wrapintype m3wrapindefault *)</I>
|
||||
PROCEDURE Name (READONLY str : TEXT := "" )
|
||||
<I> (* m3wrapoutcheck:throws *)</I>
|
||||
: NameResult RAISES {E} =
|
||||
CONST
|
||||
arg1name = "str"; <I>(* m3wrapargconst *)</I>
|
||||
VAR
|
||||
arg0 : C.char_star; <I>(* m3wrapretvar *)</I>
|
||||
arg1 : C.char_star; <I>(* m3wrapargvar *)</I>
|
||||
arg2 : C.int;
|
||||
result : RECORD
|
||||
<I> (*m3wrapretname m3wraprettype*)</I>
|
||||
unixPath : TEXT;
|
||||
<I> (*m3wrapoutname m3wrapouttype*)</I>
|
||||
checksum : CARDINAL;
|
||||
END;
|
||||
BEGIN
|
||||
TRY
|
||||
arg1 := M3toC.SharedTtoS(str); <I>(* m3wrapinconv *)</I>
|
||||
IF Text.Length(arg1) > 10 THEN <I>(* m3wrapincheck *)</I>
|
||||
RAISE E("str too long");
|
||||
END;
|
||||
<I> (* m3wrapretraw m3wrapargraw *)</I>
|
||||
arg0 := MessyToUnix (arg1, arg2);
|
||||
result.unixPath := M3toC.CopyStoT(arg0); <I>(* m3wrapretconv *)</I>
|
||||
result.checksum := arg2; <I>(* m3wrapoutconv *)</I>
|
||||
IF result.checksum = 0 THEN <I>(* m3wrapoutcheck *)</I>
|
||||
RAISE E("invalid checksum");
|
||||
END;
|
||||
FINALLY
|
||||
M3toC.FreeSharedS(str, arg1); <I>(* m3wrapfreearg *)</I>
|
||||
END;
|
||||
END Name;
|
||||
</pre></div>
|
||||
|
||||
|
||||
<H2><a name="Modula3_hints">31.5 More hints to the generator</a></H2>
|
||||
|
||||
|
||||
<H3><a name="Modula3_features">31.5.1 Features</a></H3>
|
||||
|
||||
|
||||
<table border summary="Modula-3 features">
|
||||
<tr>
|
||||
<th>Feature</th>
|
||||
<th>Example</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>multiretval</td>
|
||||
<td><tt>%m3multiretval get_box;</tt> or
|
||||
<tt>%feature("modula3:multiretval") get_box;</tt></td>
|
||||
<td>Let the denoted function return a <tt>RECORD</tt>
|
||||
rather than a plain value.
|
||||
This <tt>RECORD</tt> contains all arguments with "out" direction
|
||||
including the return value of the C function (if there is one).
|
||||
If more than one argument is "out"
|
||||
then the function <b>must</b> have the <tt>multiretval</tt> feature activated,
|
||||
but it is explicitly requested from the user to prevent mistakes.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>constnumeric</td>
|
||||
<td><tt>%constnumeric(12) twelve;</tt> or
|
||||
<tt>%feature("constnumeric", "12") twelve;</tt></td>
|
||||
<td>This feature can be used to tell Modula-3's back-end of SWIG
|
||||
the value of an identifier.
|
||||
This is necessary in the cases
|
||||
where it was defined by a non-trivial C expression.
|
||||
This feature is used by the
|
||||
<tt>-generateconst</tt> <a href="#Modula3_commandline">option</a>.
|
||||
In future it may be generalized to other kind of values
|
||||
such as strings.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<H3><a name="Modula3_pragmas">31.5.2 Pragmas</a></H3>
|
||||
|
||||
|
||||
<table border summary="Modula-3 pragmas">
|
||||
<tr>
|
||||
<th>Pragma</th>
|
||||
<th>Example</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>unsafe</td>
|
||||
<td><tt>%pragma(modula3) unsafe="true";</tt></td>
|
||||
<td>Mark the raw interface modules as <tt>UNSAFE</tt>.
|
||||
This will be necessary in many cases.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>library</td>
|
||||
<td><tt>%pragma(modula3) library="m3fftw";</tt></td>
|
||||
<td>Specifies the library name for the wrapper library to be created.
|
||||
It should be distinct from the name of the library to be wrapped.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<H2><a name="Modula3_remarks">31.6 Remarks</a></H2>
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
The Modula-3 part of SWIG doesn't try to generate nicely formatted code.
|
||||
If you need to read the generated code, use <tt>m3pp</tt> to postprocess the
|
||||
Modula files.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,352 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Working with Modules</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<H1><a name="Modules">19 Working with Modules</a></H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#Modules_introduction">Modules Introduction</a>
|
||||
<li><a href="#Modules_nn1">Basics</a>
|
||||
<li><a href="#Modules_nn2">The SWIG runtime code</a>
|
||||
<li><a href="#Modules_external_run_time">External access to the runtime</a>
|
||||
<li><a href="#Modules_nn4">A word of caution about static libraries</a>
|
||||
<li><a href="#Modules_nn5">References</a>
|
||||
<li><a href="#Modules_nn6">Reducing the wrapper file size</a>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<H2><a name="Modules_introduction">19.1 Modules Introduction</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
Each invocation of SWIG requires a module name to be specified.
|
||||
The module name is used to name the resulting target language extension module.
|
||||
Exactly what this means and what the name is used for
|
||||
depends on the target language, for example the name can define
|
||||
a target language namespace or merely be a useful name for naming files or helper classes.
|
||||
Essentially, a module comprises target language wrappers for a chosen collection of global variables/functions, structs/classes and other C/C++ types.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The module name can be supplied in one of two ways.
|
||||
The first is to specify it with the special <tt>%module</tt>
|
||||
directive. This directive must appear at the beginning of the interface file.
|
||||
The general form of this directive is:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
<tt>%module(option1="value1", option2="value2", ...) modulename</tt>
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
where the modulename is mandatory and the options add one or more optional additional features.
|
||||
Typically no options are specified, for example:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
<tt>%module mymodule</tt>
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
The second way to specify the module name is with the <tt>-module</tt> command line option, for example <tt>-module mymodule</tt>.
|
||||
If the module name is supplied on the command line, it overrides the name specified by the
|
||||
<tt>%module</tt> directive.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When first working with SWIG, users commonly start by creating a
|
||||
single module. That is, you might define a single SWIG interface that
|
||||
wraps some set of C/C++ code. You then compile all of the generated
|
||||
wrapper code together and use it. For large applications, however,
|
||||
this approach is problematic---the size of the generated wrapper code
|
||||
can be rather large. Moreover, it is probably easier to manage the
|
||||
target language interface when it is broken up into smaller pieces.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This chapter describes the problem of using SWIG in programs
|
||||
where you want to create a collection of modules.
|
||||
Each module in the collection is created via separate invocations of SWIG.
|
||||
</p>
|
||||
|
||||
<H2><a name="Modules_nn1">19.2 Basics</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
The basic usage case with multiple modules is when modules do not have
|
||||
cross-references (ie. when wrapping multiple independent C APIs). In that case,
|
||||
swig input files should just work out of the box - you simply create multiple
|
||||
wrapper .cxx files, link them into your application, and insert/load each in the
|
||||
scripting language runtime as you would do for the single module case.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A bit more complex is the case in which modules need to share information.
|
||||
For example, when one module extends the class of another by deriving from
|
||||
it:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
// File: base.h
|
||||
class base {
|
||||
public:
|
||||
int foo();
|
||||
};
|
||||
</pre></div>
|
||||
|
||||
|
||||
<div class="code"><pre>
|
||||
// File: base_module.i
|
||||
%module base_module
|
||||
|
||||
%{
|
||||
#include "base.h"
|
||||
%}
|
||||
%include "base.h"
|
||||
</pre></div>
|
||||
|
||||
|
||||
<div class="code"><pre>
|
||||
// File: derived_module.i
|
||||
%module derived_module
|
||||
|
||||
%import "base_module.i"
|
||||
|
||||
%inline %{
|
||||
class derived : public base {
|
||||
public:
|
||||
int bar();
|
||||
};
|
||||
%}
|
||||
</pre></div>
|
||||
|
||||
<p>To create the wrapper properly, module <tt>derived_module</tt> needs to know about the
|
||||
<tt>base</tt> class and that its interface is covered in another module. The
|
||||
line <tt>%import "base_module.i"</tt> lets SWIG know exactly that. Often
|
||||
the <tt>.h</tt> file is passed to <tt>%import</tt> instead of the <tt>.i</tt>,
|
||||
which unfortunately doesn't work for all language modules. For example, Python requires the
|
||||
name of module that the base class exists in so that the proxy classes can fully inherit the
|
||||
base class's methods. Typically you will get a warning when the module name is missing, eg:
|
||||
</p>
|
||||
|
||||
<div class="shell"> <pre>
|
||||
derived_module.i:8: Warning 401: Base class 'base' ignored - unknown module name for base. Either
|
||||
import
|
||||
the appropriate module interface file or specify the name of the module in the %import directive.
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
It is sometimes desirable to import the header file rather than the interface file and overcome
|
||||
the above warning.
|
||||
For example in the case of the imported interface being quite large, it may be desirable to
|
||||
simplify matters and just import a small header file of dependent types.
|
||||
This can be done by specifying the optional <tt>module</tt> attribute in the <tt>%import</tt> directive.
|
||||
The <tt>derived_module.i</tt> file shown above could be replaced with the following:
|
||||
|
||||
<div class="code"><pre>
|
||||
// File: derived_module.i
|
||||
%module derived_module
|
||||
|
||||
%import(module="base_module") "base.h"
|
||||
|
||||
%inline %{
|
||||
class derived : public base {
|
||||
public:
|
||||
int bar();
|
||||
};
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Note that "base_module" is the module name and is the same as that specified in <tt>%module</tt>
|
||||
in <tt>base_module.i</tt> as well as the <tt>%import</tt> in <tt>derived_module.i</tt>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Another issue
|
||||
to beware of is that multiple dependent wrappers should not be linked/loaded
|
||||
in parallel from multiple threads as SWIG provides no locking - for more on that
|
||||
issue, read on.
|
||||
</p>
|
||||
|
||||
<H2><a name="Modules_nn2">19.3 The SWIG runtime code</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
Many of SWIG's target languages generate a set of functions commonly known as
|
||||
the "SWIG runtime." These functions are primarily related to the runtime type
|
||||
system which checks pointer types and performs other tasks such as proper
|
||||
casting of pointer values in C++. As a general rule, the statically typed target
|
||||
languages, such as Java, use the language's built in static type checking and
|
||||
have no need for a SWIG runtime. All the dynamically typed / interpreted
|
||||
languages rely on the SWIG runtime.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The runtime functions are private to each SWIG-generated module. That is, the
|
||||
runtime functions are declared with "static" linkage and are visible only to the
|
||||
wrapper functions defined in that module. The only problem with this approach is
|
||||
that when more than one SWIG module is used in the same application, those
|
||||
modules often need to share type information. This is especially true for C++
|
||||
programs where SWIG must collect and share information about inheritance
|
||||
relationships that cross module boundaries.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To solve the problem of sharing information across modules, a pointer to the
|
||||
type information is stored in a global variable in the target language
|
||||
namespace. During module initialization, type information is loaded into the
|
||||
global data structure of type information from all modules.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
There are a few trade offs with this approach. This type information is global
|
||||
across all SWIG modules loaded, and can cause type conflicts between modules
|
||||
that were not designed to work together. To solve this approach, the SWIG
|
||||
runtime code uses a define SWIG_TYPE_TABLE to provide a unique type table. This
|
||||
behavior can be enabled when compiling the generated _wrap.cxx or _wrap.c file
|
||||
by adding -DSWIG_TYPE_TABLE=myprojectname to the command line argument.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Then, only modules compiled with SWIG_TYPE_TABLE set to myprojectname will share
|
||||
type information. So if your project has three modules, all three should be
|
||||
compiled with -DSWIG_TYPE_TABLE=myprojectname, and then these three modules will
|
||||
share type information. But any other project's types will not interfere or
|
||||
clash with the types in your module.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Another issue relating to the global type table is thread safety. If two modules
|
||||
try and load at the same time, the type information can become corrupt. SWIG
|
||||
currently does not provide any locking, and if you use threads, you must make
|
||||
sure that modules are loaded serially. Be careful if you use threads and the
|
||||
automatic module loading that some scripting languages provide. One solution is
|
||||
to load all modules before spawning any threads, or use SWIG_TYPE_TABLE to
|
||||
separate type tables so they do not clash with each other.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Lastly, SWIG uses a #define SWIG_RUNTIME_VERSION, located in Lib/swigrun.swg and
|
||||
near the top of every generated module. This number gets incremented when the
|
||||
data structures change, so that SWIG modules generated with different versions
|
||||
can peacefully coexist. So the type structures are separated by the
|
||||
(SWIG_TYPE_TABLE, SWIG_RUNTIME_VERSION) pair, where by default SWIG_TYPE_TABLE
|
||||
is empty. Only modules compiled with the same pair will share type information.
|
||||
</p>
|
||||
|
||||
<H2><a name="Modules_external_run_time">19.4 External access to the runtime</a></H2>
|
||||
|
||||
|
||||
<p>As described in <a href="Typemaps.html#Typemaps_runtime_type_checker">The run-time type checker</a>,
|
||||
the functions <tt>SWIG_TypeQuery</tt>, <tt>SWIG_NewPointerObj</tt>, and others sometimes need
|
||||
to be called. Calling these functions from a typemap is supported, since the typemap code
|
||||
is embedded into the <tt>_wrap.c</tt> file, which has those declarations available. If you need
|
||||
to call the SWIG run-time functions from another C file, there is one header you need
|
||||
to include. To generate the header that needs to be included, SWIG can be run in a different
|
||||
mode via <tt>-external-runtime</tt> to generate the run-time instead of the normal mode of
|
||||
processing an input interface file. For example:
|
||||
|
||||
<div class="shell"><pre>
|
||||
$ swig -python -external-runtime <filename>
|
||||
</pre></div>
|
||||
|
||||
<p>The filename argument is optional and if it is not passed, then the default filename will
|
||||
be something like <tt>swigpyrun.h</tt>, depending on the language. This header file should
|
||||
be treated like any of the other _wrap.c output files, and should be regenerated when the
|
||||
_wrap files are. After including this header, your code will be able to call <tt>SWIG_TypeQuery</tt>,
|
||||
<tt>SWIG_NewPointerObj</tt>, <tt>SWIG_ConvertPtr</tt> and others. The exact argument parameters
|
||||
for these functions might differ between language modules; please check the language module chapters
|
||||
for more information.</p>
|
||||
|
||||
<p>Inside this header the functions are declared static and are included inline into the file,
|
||||
and thus the file does not need to be linked against any SWIG libraries or code (you might still
|
||||
need to link against the language libraries like libpython-2.3). Data is shared between this
|
||||
file and the _wrap.c files through a global variable in the scripting language. It is also
|
||||
possible to copy this header file along with the generated wrapper files into your own package,
|
||||
so that you can distribute a package that can be compiled without SWIG installed (this works
|
||||
because the header file is self-contained, and does not need to link with anything).</p>
|
||||
|
||||
<p>
|
||||
This header will also use the -DSWIG_TYPE_TABLE described above, so when
|
||||
compiling any code which includes the generated header file should define the
|
||||
SWIG_TYPE_TABLE to be the same as the module whose types you are trying to
|
||||
access.
|
||||
</p>
|
||||
|
||||
<H2><a name="Modules_nn4">19.5 A word of caution about static libraries</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
When working with multiple SWIG modules, you should take care not to use static
|
||||
libraries. For example, if you have a static library <tt>libfoo.a</tt> and you link a collection
|
||||
of SWIG modules with that library, each module will get its own private copy of the library code inserted
|
||||
into it. This is very often <b>NOT</b> what you want and it can lead to unexpected or bizarre program
|
||||
behavior. When working with dynamically loadable modules, you should try to work exclusively with shared libraries.
|
||||
</p>
|
||||
|
||||
<H2><a name="Modules_nn5">19.6 References</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
Due to the complexity of working with shared libraries and multiple modules, it might be a good idea to consult
|
||||
an outside reference. John Levine's "Linkers and Loaders" is highly recommended.
|
||||
</p>
|
||||
|
||||
<H2><a name="Modules_nn6">19.7 Reducing the wrapper file size</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
Using multiple modules with the <tt>%import</tt> directive is the most common approach to modularising large projects.
|
||||
In this way a number of different wrapper files can be generated, thereby avoiding the generation of a single large wrapper file.
|
||||
There are a couple of alternative solutions for reducing the size of a wrapper file through the use of command line options and features.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>-fcompact</b><br>
|
||||
This command line option will compact the size of the wrapper file without changing the code generated into the wrapper file.
|
||||
It simply removes blank lines and joins lines of code together.
|
||||
This is useful for compilers that have a maximum file size that can be handled.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>-fvirtual</b><br>
|
||||
This command line option will remove the generation of superfluous virtual method wrappers.
|
||||
Consider the following inheritance hierarchy:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
struct Base {
|
||||
virtual void method();
|
||||
...
|
||||
};
|
||||
|
||||
struct Derived : Base {
|
||||
virtual void method();
|
||||
...
|
||||
};
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Normally wrappers are generated for both methods, whereas this command line option will suppress the generation of a wrapper for <tt>Derived::method</tt>.
|
||||
Normal polymorphic behaviour remains as <tt>Derived::method</tt> will still be called should you have
|
||||
a <tt>Derived</tt> instance and call the wrapper for <tt>Base::method</tt>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>%feature("compactdefaultargs")</b><br>
|
||||
This feature can reduce the number of wrapper methods when wrapping methods with default arguments. The section on <a href="SWIGPlus.html#SWIGPlus_default_args">default arguments</a> discusses the feature and its limitations.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,181 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and MzScheme/Racket</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
|
||||
<H1><a name="Mzscheme">37 SWIG and MzScheme/Racket</a></H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#MzScheme_nn2">Creating native structures</a>
|
||||
<li><a href="#MzScheme_simple">Simple example</a>
|
||||
<li><a href="#MzScheme_external_docs">External documentation</a>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
This section contains information on SWIG's support of Racket, formally known as MzScheme.
|
||||
|
||||
<H2><a name="MzScheme_nn2">37.1 Creating native structures</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
Example interface file:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
/* define a macro for the struct creation */
|
||||
%define handle_ptr(TYPE, NAME)
|
||||
%typemap(argout) TYPE *NAME{
|
||||
Scheme_Object *o = SWIG_NewStructFromPtr($1, $*1_mangle);
|
||||
SWIG_APPEND_VALUE(o);
|
||||
}
|
||||
|
||||
%typemap(in, numinputs=0) TYPE *NAME (TYPE temp) {
|
||||
$1 = &temp;
|
||||
}
|
||||
%enddef
|
||||
|
||||
/* setup the typemaps for the pointer to an output parameter cntrs */
|
||||
handle_ptr(struct diag_cntrs, cntrs);
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Then in scheme, you can use regular struct access procedures like
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
; suppose a function created a struct foo as
|
||||
; (define foo (make-diag-cntrs (#x1 #x2 #x3) (make-inspector))
|
||||
; Then you can do
|
||||
(format "0x~x" (diag-cntrs-field1 foo))
|
||||
(format "0x~x" (diag-cntrs-field2 foo))
|
||||
;etc...
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<H2><a name="MzScheme_simple">37.2 Simple example</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
A few examples are available in the Examples/mzscheme directory.
|
||||
The code and log of a session using SWIG below should help getting started.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
C header file:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
// example.h
|
||||
int fact(int n);
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
C source code:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
// File: example.c
|
||||
#include "example.h"
|
||||
|
||||
int fact(int n) {
|
||||
if (n < 0) { /* This should probably return an error, but this is simpler */
|
||||
return 0;
|
||||
}
|
||||
if (n == 0) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
/* testing for overflow would be a good idea here */
|
||||
return n * fact(n-1);
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
SWIG interface file:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
/* File: example.i */
|
||||
%module example
|
||||
|
||||
%{
|
||||
#include "example.h"
|
||||
%}
|
||||
|
||||
int fact(int n);
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The session below using the above files is on an OS X machine, but the points to be made are more general. On OS X, libtool is the tool which creates libraries, which are named .dylib, rather than .so on other unixes, or .dll on Windows.
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
% swig -mzscheme -declaremodule example.i
|
||||
% gcc -c -m32 -o example.o example.c # force 32-bit object file (mzscheme is 32-bit only)
|
||||
% libtool -dynamic -o libexample.dylib example.o # make it into a library
|
||||
% ls # what've we got so far?
|
||||
example.c example.o
|
||||
example.h example_wrap.c
|
||||
example.i libexample.dylib*
|
||||
% mzc --cgc --cc example_wrap.c # compile the wrapping code
|
||||
% LDFLAGS="-L. -lexample" mzc --ld example_wrap.dylib example_wrap.o # ...and link it
|
||||
% mzscheme -e '(path->string (build-path "compiled" "native" (system-library-subpath)))'
|
||||
"compiled/native/i386-macosx/3m"
|
||||
% mkdir -p compiled/native/i386-macosx/3m # move the extension library to a magic place
|
||||
% mv example_wrap.dylib compiled/native/i386-macosx/3m/example_ss.dylib
|
||||
% mzscheme
|
||||
Welcome to MzScheme v4.2.4 [3m], Copyright (c) 2004-2010 PLT Scheme Inc.
|
||||
> (require "example.ss")
|
||||
> (fact 5)
|
||||
120
|
||||
> ^D
|
||||
% echo 'It works!'
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
|
||||
<p>
|
||||
Some points of interest:
|
||||
</p>
|
||||
<ul>
|
||||
<li> This is on a 64-bit machine, so we have to include the -m32 option when building the object file
|
||||
<li> If you want to declare a scheme module (and you probably do), it's important that you include the -declaremodule option to swig (if you miss this out, it'll appear to work, but fail later).
|
||||
<li> Use mzc to compile and then link the wrapped code. You'll probably need to adjust the link flags to refer to the library you're wrapping (you can either do this with an LDFLAGS declaration, as here, or with multiple ++ldf options to mzc).
|
||||
<li> Create the directory with path (build-path "compiled" "native" (system-library-subpath)) and move the freshly-generated .dylib to there, changing its name to module-name_ss.dylib. After that, you can REQUIRE the new module with (require "module-name.ss").
|
||||
<li> The above requests mzc to create an extension using the CGC garbage-collector. The alternative -- the 3m collector -- has generally better performance, but work is still required for SWIG to emit code which is compatible with it.
|
||||
</ul>
|
||||
|
||||
<H2><a name="MzScheme_external_docs">37.3 External documentation</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
See the <a href="https://docs.racket-lang.org/inside/index.html">C API</a> for more description of using the mechanism for adding extensions. The main documentation is <a href="https://docs.racket-lang.org/">here</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Tip: mzc's --vv option is very useful for debugging the inevitable library problems you'll encounter.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,909 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and Octave</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
|
||||
<H1><a name="Octave">29 SWIG and Octave</a></H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#Octave_nn2">Preliminaries</a>
|
||||
<li><a href="#Octave_nn3">Running SWIG</a>
|
||||
<ul>
|
||||
<li><a href="#Octave_nn4">Command-line options</a>
|
||||
<li><a href="#Octave_nn5">Compiling a dynamic module</a>
|
||||
<li><a href="#Octave_nn6">Using your module</a>
|
||||
</ul>
|
||||
<li><a href="#Octave_nn7">A tour of basic C/C++ wrapping</a>
|
||||
<ul>
|
||||
<li><a href="#Octave_nn8">Modules</a>
|
||||
<li><a href="#Octave_nn9">Functions</a>
|
||||
<li><a href="#Octave_nn10">Global variables</a>
|
||||
<li><a href="#Octave_nn11">Constants and enums</a>
|
||||
<li><a href="#Octave_nn12">Pointers</a>
|
||||
<li><a href="#Octave_nn13">Structures and C++ classes</a>
|
||||
<li><a href="#Octave_nn15">C++ inheritance</a>
|
||||
<li><a href="#Octave_nn17">C++ overloaded functions</a>
|
||||
<li><a href="#Octave_nn18">C++ operators</a>
|
||||
<li><a href="#Octave_nn19">Class extension with %extend</a>
|
||||
<li><a href="#Octave_nn20">C++ templates</a>
|
||||
<li><a href="#Octave_nn21">C++ Smart Pointers</a>
|
||||
<ul>
|
||||
<li><a href="#Octave_smart_pointers_shared_ptr">The shared_ptr Smart Pointer</a>
|
||||
<li><a href="#Octave_smart_pointers_generic">Generic Smart Pointers</a>
|
||||
</ul>
|
||||
<li><a href="#Octave_nn22">Directors (calling Octave from C++ code)</a>
|
||||
<li><a href="#Octave_nn23">Threads</a>
|
||||
<li><a href="#Octave_nn24">Memory management</a>
|
||||
<li><a href="#Octave_nn25">STL support</a>
|
||||
<li><a href="#Octave_nn26">Matrix typemaps</a>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
Octave is a high-level language intended for numerical programming that is mostly compatible with MATLAB.
|
||||
More information can be found at <a href="http://www.gnu.org/software/octave/">Octave web site</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This chapter is intended to give an introduction to using the module. You should also read the SWIG documentation that is not specific to Octave.
|
||||
Also, there are a dozen or so examples in the Examples/octave directory, and hundreds in the test suite (Examples/test-suite and Examples/test-suite/octave).
|
||||
</p>
|
||||
|
||||
<H2><a name="Octave_nn2">29.1 Preliminaries</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG is regularly tested against the following versions of Octave: 3.8, 4.0, 4.2.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Every effort is made to maintain backward compatibility with older versions of Octave.
|
||||
This cannot be guaranteed however, as in recent times new Octave releases have required nontrivial updates to SWIG, which may break backward compatibility for older Octave versions against which SWIG is not regularly tested.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The SWIG runtime exports the function <tt>swig_octave_prereq()</tt> for checking the version of Octave.
|
||||
</p>
|
||||
|
||||
<H2><a name="Octave_nn3">29.2 Running SWIG</a></H2>
|
||||
|
||||
|
||||
<p>
|
||||
Let's start with a very simple SWIG interface file, example.i:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%module swigexample
|
||||
%{
|
||||
#include "example.h"
|
||||
%}
|
||||
int gcd(int x, int y);
|
||||
extern double Foo; </pre></div>
|
||||
|
||||
<p>
|
||||
To build an Octave module when wrapping C code, run SWIG using the <tt>-octave</tt> option:
|
||||
</p>
|
||||
|
||||
<div class="shell"><pre>$ swig -octave -o example_wrap.cpp example.i </pre></div>
|
||||
|
||||
<p>
|
||||
The <tt>-c++</tt> option is also required when wrapping C++ code:
|
||||
</p>
|
||||
|
||||
|
||||
<div class="shell"><pre>$ swig -octave -c++ -o example_wrap.cpp example.i </pre></div>
|
||||
|
||||
<p>
|
||||
This creates a C++ source file "example_wrap.cpp". A C++ file is generated even when wrapping C code as Octave is itself written in C++ and requires wrapper code to be in the same language. The generated C++ source file contains the low-level wrappers that need to be compiled and linked with the rest of your C/C++ application (in this case, the gcd implementation) to create an extension module.
|
||||
</p>
|
||||
|
||||
<H3><a name="Octave_nn4">29.2.1 Command-line options</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
The swig command line has a number of options you can use, like to redirect its output. Use <tt>swig -help</tt> to learn about these.
|
||||
Options specific to the Octave module are:
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>$ swig -octave -help
|
||||
...
|
||||
Octave Options (available with -octave)
|
||||
-globals <em>name</em> - Set <em>name</em> used to access C global variables [default: 'cvar']
|
||||
Use '.' to load C global variables into module namespace
|
||||
-opprefix <em>str</em> - Prefix <em>str</em> for global operator functions [default: 'op_']
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
The <em>-globals</em> option sets the name of the variable which is the namespace for C global variables exported by the module.
|
||||
The special name "." loads C global variables into the module namespace, i.e. alongside C functions and structs exported by the module.
|
||||
The <em>-opprefix</em> options sets the prefix of the names of global/friend <a href="#Octave_nn18">operator</a> functions.
|
||||
</p>
|
||||
|
||||
<H3><a name="Octave_nn5">29.2.2 Compiling a dynamic module</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Octave modules are DLLs/shared objects having the ".oct" suffix.
|
||||
Building an oct file is usually done with the mkoctfile command (either within Octave itself, or from the shell). For example,
|
||||
</p>
|
||||
|
||||
<div class="shell"><pre>
|
||||
$ swig -octave -c++ -o example_wrap.cpp example.i
|
||||
$ mkoctfile example_wrap.cpp example.c
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
where "example.c" is the file containing the gcd() implementation.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
mkoctfile can also be used to extract the build parameters required to invoke the compiler and linker yourself. See the Octave manual and mkoctfile man page.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
mkoctfile will produce "swigexample.oct", which contains the compiled extension module. Loading it into Octave is then a matter of invoking
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>octave:1> swigexample</pre></div>
|
||||
|
||||
<H3><a name="Octave_nn6">29.2.3 Using your module</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Assuming all goes well, you will be able to do this:
|
||||
<br>
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>$ octave -q
|
||||
octave:1> swigexample
|
||||
octave:2> swigexample.gcd(4, 6)
|
||||
ans = 2
|
||||
octave:3> swigexample.cvar.Foo
|
||||
ans = 3
|
||||
octave:4> swigexample.cvar.Foo=4;
|
||||
octave:5> swigexample.cvar.Foo
|
||||
ans = 4 </pre></div>
|
||||
|
||||
<H2><a name="Octave_nn7">29.3 A tour of basic C/C++ wrapping</a></H2>
|
||||
|
||||
|
||||
<H3><a name="Octave_nn8">29.3.1 Modules</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
The SWIG module directive specifies the name of the Octave module. If you specify "module swigexample", then in Octave everything in the module will be accessible under "swigexample", as in the above example. When choosing a module name, make sure you don't use the same name as a built-in Octave command or standard module name.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When Octave is asked to invoke <tt>swigexample</tt>, it will try to find the ".m" or ".oct" file that defines the function "swigexample". You therefore need to make sure that "swigexample.oct" is in Octave's search path, which can be specified with the environment variable "OCTAVE_PATH".
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To load an Octave module, simply type its name:
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
octave:1> swigexample;
|
||||
octave:2> gcd(4, 6)
|
||||
ans = 2
|
||||
octave:3> cvar.Foo
|
||||
ans = 3
|
||||
octave:4> cvar.Foo=4;
|
||||
octave:5> cvar.Foo
|
||||
ans = 4
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Modules can also be loaded from within functions, even before being loaded in the base context.
|
||||
If the module is also used in the base context, however, it must first be loaded again:
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
octave:1> function l = my_lcm(a, b)
|
||||
> swigexample
|
||||
> l = abs(a*b)/swigexample.gcd(a, b);
|
||||
> endfunction
|
||||
octave:2> my_lcm(4, 6)
|
||||
ans = 12
|
||||
octave:3> swigexample.gcd(4, 6)
|
||||
error: can't perform indexing operations for <unknown type> type
|
||||
octave:3> swigexample;
|
||||
octave:4> swigexample.gcd(4, 6)
|
||||
ans = 2
|
||||
</pre></div>
|
||||
|
||||
<H3><a name="Octave_nn9">29.3.2 Functions</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Global functions are wrapped as new Octave built-in functions. For example,
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>%module swigexample
|
||||
int fact(int n); </pre></div>
|
||||
|
||||
<p>
|
||||
creates a built-in function <tt>swigexample.fact(n)</tt> that works exactly like you think it does:
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>octave:1> swigexample.fact(4)
|
||||
24 </pre></div>
|
||||
|
||||
<H3><a name="Octave_nn10">29.3.3 Global variables</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Global variables are a little special in Octave. Given a global variable:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>%module swigexample
|
||||
extern double Foo;
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
To expose variables, SWIG actually generates two functions, to get and set the value. In this case, Foo_set and Foo_set would be generated. SWIG then automatically calls these functions when you get and set the variable-- in the former case creating a local copy in the interpreter of the C variables, and in the latter case copying an interpreter variables onto the C variable.
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>octave:1> swigexample;
|
||||
octave:2> c=swigexample.cvar.Foo
|
||||
c = 3
|
||||
octave:3> swigexample.cvar.Foo=4;
|
||||
octave:4> c
|
||||
c = 3
|
||||
octave:5> swigexample.cvar.Foo
|
||||
ans = 4</pre></div>
|
||||
|
||||
<p>
|
||||
If a variable is marked with the %immutable directive then any attempts to set this variable will cause an Octave error. Given a global variable:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>%module swigexample
|
||||
%immutable;
|
||||
extern double Foo;
|
||||
%mutable;
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
SWIG will allow the reading of <tt>Foo</tt> but when a set attempt is made, an error function will be called.
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>octave:1> swigexample
|
||||
octave:2> swigexample.Foo=4
|
||||
error: attempt to set immutable member variable
|
||||
error: assignment failed, or no method for `swig_type = scalar'
|
||||
error: evaluating assignment expression near line 2, column 12 </pre></div>
|
||||
|
||||
<p>
|
||||
It is possible to add new functions or variables to the module. This also allows the user to rename/remove existing functions and constants (but not linked variables, mutable or immutable). Therefore users are recommended to be careful when doing so.
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>octave:1> swigexample;
|
||||
octave:2> swigexample.PI=3.142;
|
||||
octave:3> swigexample.PI
|
||||
ans = 3.1420 </pre></div>
|
||||
|
||||
<H3><a name="Octave_nn11">29.3.4 Constants and enums</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Because Octave doesn't really have the concept of constants, C/C++ constants are not really constant in Octave. They are actually just a copy of the value into the Octave interpreter. Therefore they can be changed just as any other value. For example given some constants:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>%module swigexample
|
||||
%constant int ICONST=42;
|
||||
#define SCONST "Hello World"
|
||||
enum Days{SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY};
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
This is 'effectively' converted into the following Octave code:
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>swigexample.ICONST=42
|
||||
swigexample.SCONST="Hello World"
|
||||
swigexample.SUNDAY=0
|
||||
.... </pre></div>
|
||||
|
||||
<H3><a name="Octave_nn12">29.3.5 Pointers</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
C/C++ pointers are fully supported by SWIG. Furthermore, SWIG has no problem working with incomplete type information. Given a wrapping of the <file.h> interface:
|
||||
C/C++ pointers are fully supported by SWIG. Furthermore, SWIG has no problem working with incomplete type information. Given a wrapping of the <file.h> interface:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>%module swigexample
|
||||
FILE *fopen(const char *filename, const char *mode);
|
||||
int fputs(const char *, FILE *);
|
||||
int fclose(FILE *);
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
When wrapped, you will be able to use the functions in a natural way from Octave. For example:
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
octave:1> swigexample;
|
||||
octave:2> f=swigexample.fopen("w", "junk");
|
||||
octave:3> swigexample.fputs("Hello world", f);
|
||||
octave:4> swigexample.fclose(f);
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Simply printing the value of a wrapped C++ type will print its typename. E.g.,
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>octave:1> swigexample;
|
||||
octave:2> f=swigexample.fopen("junk", "w");
|
||||
octave:3> f
|
||||
f =
|
||||
|
||||
{
|
||||
_p_FILE, ptr = 0x9b0cd00
|
||||
} </pre></div>
|
||||
|
||||
<p>
|
||||
As the user of the pointer, you are responsible for freeing it, or closing any resources associated with it (just as you would in a C program). This does not apply so strictly to classes and structs (see below).
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>octave:1> swigexample;
|
||||
octave:2> f=swigexample.fopen("not there", "r");
|
||||
error: value on right hand side of assignment is undefined
|
||||
error: evaluating assignment expression near line 2, column 2 </pre></div>
|
||||
|
||||
<H3><a name="Octave_nn13">29.3.6 Structures and C++ classes</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG wraps C structures and C++ classes by using a special Octave type called a <tt>swig_ref</tt>. A <tt>swig_ref</tt> contains a reference to one or more instances of C/C++ objects, or just the type information for an object.
|
||||
For each wrapped structure and class, a <tt>swig_ref</tt> will be exposed that has the name of the type. When invoked as a function, it creates a new object of its type and returns a <tt>swig_ref</tt> that points to that instance. This provides a very natural interface. For example,
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>struct Point{
|
||||
int x, y;
|
||||
};
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
is used as follows:
|
||||
</p>
|
||||
|
||||
<div class="targetlang">
|
||||
<pre>octave:1> swigexample;
|
||||
octave:2> p=swigexample.Point();
|
||||
octave:3> p.x=3;
|
||||
octave:4> p.y=5;
|
||||
octave:5> p.x, p.y
|
||||
ans = 3
|
||||
ans = 5
|
||||
</pre></div>
|
||||
<p>
|
||||
In C++, invoking the type object in this way calls the object's constructor.
|
||||
<tt>swig_ref</tt> objects can also be acquired by having a wrapped function return a pointer, reference, or value of a non-primitive type.
|
||||
</p>
|
||||
<p>
|
||||
The swig_ref type handles indexing operations such that usage maps closely to what you would have in C/C++.
|
||||
Structure members are accessed as in the above example, by calling set and get methods for C++ variables.
|
||||
|
||||
Methods also work as expected. For example, code wrapped in the following way
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>class Point{
|
||||
public:
|
||||
int x, y;
|
||||
Point(int _x, int _y) : x(_x), y(_y) {}
|
||||
double distance(const Point& rhs) {
|
||||
return sqrt(pow(x-rhs.x, 2)+pow(y-rhs.y, 2));
|
||||
}
|
||||
void set(int _x, int _y) {
|
||||
x=_x; y=_y;
|
||||
}
|
||||
};
|
||||
</pre></div>
|
||||
<p>
|
||||
can be used from Octave like this
|
||||
</p>
|
||||
<div class="targetlang">
|
||||
<pre>octave:1> swigexample;
|
||||
octave:2> p1=swigexample.Point(3, 5);
|
||||
octave:3> p2=swigexample.Point(1, 2);
|
||||
octave:4> p1.distance(p2)
|
||||
ans = 3.6056
|
||||
</pre></div>
|
||||
<p>
|
||||
By using the <tt>swig_this()</tt> and <tt>swig_type()</tt> functions, one can discover the pointers to and types of the underlying C/C++ object.
|
||||
</p>
|
||||
|
||||
<div class="targetlang">
|
||||
<pre>
|
||||
octave:5> swig_this(p1)
|
||||
ans = 162504808
|
||||
octave:6> swig_type(p1)
|
||||
ans = Point
|
||||
</pre></div>
|
||||
<p>
|
||||
Note that <tt>swig_ref</tt> is a reference-counted pointer to a C/C++ object/type, and as such has pass-by-reference semantics. For example if one has a allocated a single object but has two <tt>swig_ref</tt>'s pointing to it, modifying the object through either of them will change the single allocated object.
|
||||
This differs from the usual pass-by-value (copy-on-write) semantics that Octave maintains for built-in types. For example, in the following snippet, modifying <tt>b</tt> does not modify <tt>a</tt>,
|
||||
</p>
|
||||
|
||||
<div class="targetlang">
|
||||
<pre>
|
||||
octave:7> a=struct('x', 4)
|
||||
a =
|
||||
{
|
||||
x = 4
|
||||
}
|
||||
|
||||
octave:8> b=a
|
||||
b =
|
||||
{
|
||||
x = 4
|
||||
}
|
||||
|
||||
octave:9> b.y=4
|
||||
b =
|
||||
{
|
||||
x = 4
|
||||
y = 4
|
||||
}
|
||||
|
||||
octave:10> a
|
||||
a =
|
||||
{
|
||||
x = 4
|
||||
}
|
||||
</pre></div>
|
||||
<p>
|
||||
However, when dealing with wrapped objects, one gets the behavior
|
||||
</p>
|
||||
|
||||
<div class="targetlang">
|
||||
<pre>
|
||||
octave:2> a=Point(3, 5)
|
||||
a =
|
||||
|
||||
{
|
||||
Point, ptr = 0x9afbbb0
|
||||
}
|
||||
|
||||
octave:3> b=a
|
||||
b =
|
||||
|
||||
{
|
||||
Point, ptr = 0x9afbbb0
|
||||
}
|
||||
|
||||
octave:4> b.set(2, 1);
|
||||
octave:5> b.x, b.y
|
||||
ans = 2
|
||||
ans = 1
|
||||
octave:6> a.x, a.y
|
||||
ans = 2
|
||||
ans = 1
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Depending on the ownership setting of a <tt>swig_ref</tt>, it may call C++ destructors when its reference count goes to zero. See the section on memory management below for details.
|
||||
</p>
|
||||
|
||||
<H3><a name="Octave_nn15">29.3.7 C++ inheritance</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Single and multiple inheritance are fully supported. The <tt>swig_ref</tt> type carries type information along with any C++ object pointer it holds.
|
||||
This information contains the full class hierarchy. When an indexing operation (such as a method invocation) occurs,
|
||||
the tree is walked to find a match in the current class as well as any of its bases. The lookup is then cached in the <tt>swig_ref</tt>.
|
||||
</p>
|
||||
|
||||
<H3><a name="Octave_nn17">29.3.8 C++ overloaded functions</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Overloaded functions are supported, and handled as in other modules. That is,
|
||||
each overload is wrapped separately (under internal names), and a dispatch function is also emitted under the external/visible name.
|
||||
The dispatch function selects which overload to call (if any) based on the passed arguments.
|
||||
<tt>typecheck</tt> typemaps are used to analyze each argument, as well as assign precedence. See the chapter on typemaps for details.
|
||||
</p>
|
||||
|
||||
<H3><a name="Octave_nn18">29.3.9 C++ operators</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
C++ operator overloading is supported, in a way similar to other modules.
|
||||
The <tt>swig_ref</tt> type supports all unary and binary operators between itself and all other types that exist in the system at module load time. When an operator is used (where one of the operands is a <tt>swig_ref</tt>), the runtime routes the call to either a member function of the given object, or to a global function whose named is derived from the types of the operands (either both or just the lhs or rhs).
|
||||
</p>
|
||||
<p>
|
||||
For example, if <tt>a</tt> and <tt>b</tt> are SWIG variables in Octave, <tt>a+b</tt> becomes <tt>a.__add__(b)</tt>. The wrapper is then free to implement __add__ to do whatever it wants. A wrapper may define the <tt>__add__</tt> function manually, %rename some other function to it, or %rename a C++ operator to it.
|
||||
</p>
|
||||
<p>
|
||||
By default the C++ operators are renamed to their corresponding Octave operators. So without doing any work, the following interface
|
||||
</p>
|
||||
<div class="code"><pre>
|
||||
%inline {
|
||||
struct A {
|
||||
int value;
|
||||
A(int _value) : value(_value) {}
|
||||
A operator+ (const A& x) {
|
||||
return A(value+x.value);
|
||||
}
|
||||
};
|
||||
}
|
||||
</pre></div>
|
||||
<p>
|
||||
is usable from Octave like this:
|
||||
</p>
|
||||
<div class="targetlang"><pre>
|
||||
a=A(2), b=A(3), c=a+b
|
||||
assert(c.value==5);
|
||||
</pre></div>
|
||||
<p>
|
||||
Octave operators are mapped in the following way:
|
||||
</p>
|
||||
<div class="code"><pre>
|
||||
__brace__ a{args}
|
||||
__brace_asgn__ a{args} = rhs
|
||||
__paren__ a(args)
|
||||
__paren_asgn__ a(args) = rhs
|
||||
__str__ generates string rep
|
||||
__not__ !a
|
||||
__uplus__ +a
|
||||
__uminus__ -a
|
||||
__transpose__ a.'
|
||||
__hermitian__ a'
|
||||
__incr__ a++
|
||||
__decr__ a--
|
||||
__add__ a + b
|
||||
__sub__ a - b
|
||||
__mul__ a * b
|
||||
__div__ a / b
|
||||
__pow__ a ^ b
|
||||
__ldiv__ a \ b
|
||||
__lshift__ a << b
|
||||
__rshift__ a >> b
|
||||
__lt__ a < b
|
||||
__le__ a <= b
|
||||
__eq__ a == b
|
||||
__ge__ a >= b
|
||||
__gt__ a > b
|
||||
__ne__ a != b
|
||||
__el_mul__ a .* b
|
||||
__el_div__ a ./ b
|
||||
__el_pow__ a .^ b
|
||||
__el_ldiv__ a .\ b
|
||||
__el_and__ a & b
|
||||
__el_or__ a | b
|
||||
</pre></div>
|
||||
<p>
|
||||
On the C++ side, the default mappings are as follows:
|
||||
</p>
|
||||
<div class="code"><pre>
|
||||
%rename(__add__) *::operator+;
|
||||
%rename(__add__) *::operator+();
|
||||
%rename(__add__) *::operator+() const;
|
||||
%rename(__sub__) *::operator-;
|
||||
%rename(__uminus__) *::operator-();
|
||||
%rename(__uminus__) *::operator-() const;
|
||||
%rename(__mul__) *::operator*;
|
||||
%rename(__div__) *::operator/;
|
||||
%rename(__mod__) *::operator%;
|
||||
%rename(__lshift__) *::operator<<;
|
||||
%rename(__rshift__) *::operator>>;
|
||||
%rename(__el_and__) *::operator&&;
|
||||
%rename(__el_or__) *::operator||;
|
||||
%rename(__xor__) *::operator^;
|
||||
%rename(__invert__) *::operator~;
|
||||
%rename(__lt__) *::operator<;
|
||||
%rename(__le__) *::operator<=;
|
||||
%rename(__gt__) *::operator>;
|
||||
%rename(__ge__) *::operator>=;
|
||||
%rename(__eq__) *::operator==;
|
||||
%rename(__ne__) *::operator!=;
|
||||
%rename(__not__) *::operator!;
|
||||
%rename(__incr__) *::operator++;
|
||||
%rename(__decr__) *::operator--;
|
||||
%rename(__paren__) *::operator();
|
||||
%rename(__brace__) *::operator[];
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Octave can also utilise friend (i.e. non-member) operators with a simple %rename: see the example in the Examples/octave/operator directory.
|
||||
</p>
|
||||
|
||||
<H3><a name="Octave_nn19">29.3.10 Class extension with %extend</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
The %extend directive works the same as in other modules.
|
||||
</p>
|
||||
<p>
|
||||
You can use it to define special behavior, like for example defining Octave operators not mapped to C++ operators, or defining certain Octave mechanisms such as how an object prints. For example, the <tt>octave_value::{is_string, string_value, print}</tt> functions are routed to a special method <tt>__str__</tt> that can be defined inside an %extend.
|
||||
</p>
|
||||
<div class="code"><pre>
|
||||
%extend A {
|
||||
string __str__() {
|
||||
stringstream sout;
|
||||
sout<<$self->value;
|
||||
return sout.str();
|
||||
}
|
||||
}
|
||||
</pre></div>
|
||||
<p>
|
||||
Then in Octave one gets,
|
||||
</p>
|
||||
<div class="targetlang"><pre>
|
||||
octave:1> a=A(4);
|
||||
octave:2> a
|
||||
a = 4
|
||||
octave:3> printf("%s\n", a);
|
||||
4
|
||||
octave:4> a.__str__()
|
||||
4
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Similarly, Octave can use the <tt>__float__</tt> method to convert an object to a numeric value.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Octave 3.8.0 and later versions will also map unary functions X() to the corresponding <tt>__X__</tt> method, where X includes: abs(), acos(), acosh(), angle(), arg(), asin(), asinh(), atan(), atanh(), cbrt(), ceil(), conj(), cos(), cosh(), dawson(), erf(), erfc(), erfcinv(), erfcx(), erfi(), erfinv(), exp(), expm1(), finite(), fix(), floor(), gamma(), imag(), isalnum(), isalpha(), isascii(), iscntrl(), isdigit(), isgraph(), isinf(), islower(), isna(), isnan(), isprint(), ispunct(), isspace(), isupper(), isxdigit(), lgamma(), log(), log10(), log1p(), log2(), real(), round(), roundb(), signbit(), signum(), sin(), sinh(), sqrt(), tan(), tanh(), toascii(), tolower(), toupper()
|
||||
</p>
|
||||
|
||||
<H3><a name="Octave_nn20">29.3.11 C++ templates</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
C++ class and function templates are fully supported as in other modules, in that the %template directive may used to create explicit instantiations of templated types.
|
||||
For example, function templates can be instantiated as follows:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>%module swigexample
|
||||
%inline {
|
||||
template<class __scalar>
|
||||
__scalar mul(__scalar a, __scalar b) {
|
||||
return a*b;
|
||||
}
|
||||
}
|
||||
%include <std_complex.i>
|
||||
%template(mul) mul<std::complex<double> >
|
||||
%template(mul) mul<double>
|
||||
</pre></div>
|
||||
<p>
|
||||
and then used from Octave
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
octave:1> mul(4, 3)
|
||||
ans = 12
|
||||
octave:2> mul(4.2, 3.6)
|
||||
ans = 15.120
|
||||
octave:3> mul(3+4i, 10+2i)
|
||||
ans = 22 + 46i
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Similarly, class templates can be instantiated as in the following example,
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>%module swigexample
|
||||
%include <std_complex.i>
|
||||
%include <std_string.i>
|
||||
%inline {
|
||||
#include <sstream>
|
||||
template<class __scalar> class sum {
|
||||
__scalar s;
|
||||
public:
|
||||
sum(__scalar _s=0) : s(_s) {}
|
||||
sum& add(__scalar _s) {
|
||||
s+=_s;
|
||||
return *this;
|
||||
}
|
||||
std::string __str__() const {
|
||||
std::stringstream sout;
|
||||
sout<<s;
|
||||
return sout.str();
|
||||
}
|
||||
};
|
||||
}
|
||||
%template(sum_complex) sum<std::complex<double> >;
|
||||
%template(sum_double) sum<double>;
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
and then used from Octave
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
octave:2> a=sum_complex(2+3i);
|
||||
octave:3> a.add(2)
|
||||
ans =
|
||||
|
||||
(4, 3)
|
||||
octave:4> a.add(3+i)
|
||||
ans =
|
||||
|
||||
(7, 4)
|
||||
</pre></div>
|
||||
|
||||
|
||||
<H3><a name="Octave_nn21">29.3.12 C++ Smart Pointers</a></H3>
|
||||
|
||||
|
||||
<H4><a name="Octave_smart_pointers_shared_ptr">29.3.12.1 The shared_ptr Smart Pointer</a></H4>
|
||||
|
||||
|
||||
<p>
|
||||
The C++11 standard provides <tt>std::shared_ptr</tt> which was derived from the Boost
|
||||
implementation, <tt>boost::shared_ptr</tt>.
|
||||
Both of these are available for Octave in the SWIG library and usage is outlined
|
||||
in the <a href="Library.html#Library_std_shared_ptr">shared_ptr smart pointer</a> library section.
|
||||
</p>
|
||||
|
||||
|
||||
<H4><a name="Octave_smart_pointers_generic">29.3.12.2 Generic Smart Pointers</a></H4>
|
||||
|
||||
|
||||
<p>
|
||||
C++ smart pointers are fully supported as in other modules.
|
||||
</p>
|
||||
|
||||
<H3><a name="Octave_nn22">29.3.13 Directors (calling Octave from C++ code)</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
There is full support for SWIG Directors, which permits Octave code to subclass C++ classes, and implement their virtual methods.
|
||||
</p>
|
||||
<p>
|
||||
Octave has no direct support for object oriented programming, however the <tt>swig_ref</tt> type provides some of this support. You can manufacture a <tt>swig_ref</tt> using the <tt>subclass</tt> function (provided by the SWIG/Octave runtime).
|
||||
</p>
|
||||
<p>
|
||||
For example,
|
||||
</p>
|
||||
<div class="targetlang"><pre>
|
||||
octave:1> a=subclass();
|
||||
octave:2> a.my_var = 4;
|
||||
octave:3> a.my_method = @(self) printf("my_var = ", self.my_var);
|
||||
octave:4> a.my_method();
|
||||
my_var = 4
|
||||
</pre></div>
|
||||
<p>
|
||||
<tt>subclass()</tt> can also be used to subclass one or more C++ types. Suppose you have an interface defined by
|
||||
</p>
|
||||
<div class="code"><pre>
|
||||
%inline {
|
||||
class A {
|
||||
public:
|
||||
virtual my_method() {
|
||||
printf("c-side routine called\n");
|
||||
}
|
||||
};
|
||||
void call_your_method(A& a) {
|
||||
a.my_method();
|
||||
}
|
||||
}
|
||||
</pre></div>
|
||||
<p>
|
||||
Then from Octave you can say:
|
||||
</p>
|
||||
<div class="targetlang"><pre>
|
||||
octave:1> B=@() subclass(A(), @my_method);
|
||||
octave:2> function my_method(self)
|
||||
octave:3> printf("octave-side routine called\n");
|
||||
octave:4> end
|
||||
octave:5> call_your_method(B());
|
||||
octave-side routine called
|
||||
</pre></div>
|
||||
<p>
|
||||
or more concisely,
|
||||
</p>
|
||||
<div class="targetlang"><pre>
|
||||
octave:1> B=@() subclass(A(), 'my_method', @(self) printf("octave-side routine called\n"));
|
||||
octave:2> call_your_method(B());
|
||||
octave-side routine called
|
||||
</pre></div>
|
||||
<p>
|
||||
Note that you have to enable directors via the %feature directive (see other modules for this).
|
||||
</p>
|
||||
<p>
|
||||
<tt>subclass()</tt> will accept any number of C++ bases or other <tt>subclass()</tt>'ed objects, <tt>(string, octave_value)</tt> pairs, and <tt>function_handles</tt>. In the first case, these are taken as base classes; in the second case, as named members (either variables or functions, depending on whether the given value is a function handle); in the third case, as member functions whose name is taken from the given function handle. E.g.,
|
||||
</p>
|
||||
<div class="targetlang"><pre>
|
||||
octave:1> B=@(some_var=2) subclass(A(), 'some_var', some_var, @some_func, 'another_func',
|
||||
@(self) do_stuff())
|
||||
</pre></div>
|
||||
<p>
|
||||
You can also assign non-C++ member variables and functions after construct time. There is no support for non-C++ static members.
|
||||
</p>
|
||||
<p>
|
||||
There is limited support for explicitly referencing C++ bases. So, in the example above, we could have
|
||||
</p>
|
||||
<div class="targetlang"><pre>
|
||||
octave:1> B=@() subclass(A(), @my_method);
|
||||
octave:2> function my_method(self)
|
||||
octave:3> self.A.my_method();
|
||||
octave:4> printf("octave-side routine called\n");
|
||||
octave:5> end
|
||||
octave:6> call_your_method(B());
|
||||
c-side routine called
|
||||
octave-side routine called
|
||||
</pre></div>
|
||||
|
||||
<H3><a name="Octave_nn23">29.3.14 Threads</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
The use of threads in wrapped Director code is not supported; i.e., an Octave-side implementation of a C++ class must be called from the Octave interpreter's thread. Anything fancier (apartment/queue model, whatever) is left to the user. Without anything fancier, this amounts to the limitation that Octave must drive the module... like, for example, an optimization package that calls Octave to evaluate an objective function.
|
||||
</p>
|
||||
|
||||
<H3><a name="Octave_nn24">29.3.15 Memory management</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
As noted above, <tt>swig_ref</tt> represents a reference counted pointer to a C/C++-side object. It also contains a flag indicating whether Octave or the C/C++ code owns the object. If Octave owns it, any destructors will be called when the reference count reaches zero. If the C/C++ side owns the object, then destructors will not be called when the reference count goes to zero.
|
||||
</p>
|
||||
<p>
|
||||
For example,
|
||||
<div class="code"><pre>
|
||||
%inline {
|
||||
class A {
|
||||
public:
|
||||
A() { printf("A constructing\n"); }
|
||||
~A() { printf("A destructing\n"); }
|
||||
};
|
||||
}
|
||||
</pre></div>
|
||||
<p>
|
||||
Would produce this behavior in Octave:
|
||||
</p>
|
||||
<div class="targetlang"><pre>
|
||||
octave:1> a=A();
|
||||
A constructing
|
||||
octave:2> b=a;
|
||||
octave:3> clear a;
|
||||
octave:4> b=4;
|
||||
A destructing
|
||||
</pre></div>
|
||||
<p>
|
||||
The %newobject directive may be used to control this behavior for pointers returned from functions.
|
||||
<p>
|
||||
In the case where one wishes for the C++ side to own an object that was created in Octave (especially a Director object), one can use the __disown() method to invert this logic. Then letting the Octave reference count go to zero will not destroy the object, but destroying the object will invalidate the Octave-side object if it still exists (and call destructors of other C++ bases in the case of multiple inheritance/<tt>subclass()</tt>'ing).
|
||||
</p>
|
||||
|
||||
<H3><a name="Octave_nn25">29.3.16 STL support</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Various STL library files are provided for wrapping STL containers.
|
||||
</p>
|
||||
|
||||
<H3><a name="Octave_nn26">29.3.17 Matrix typemaps</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
Octave provides a rich set of classes for dealing with matrices. Currently there are no built-in typemaps to deal with those. However, these are relatively straight forward for users to add themselves (see the docs on typemaps). Without much work (a single typemap decl-- say, 5 lines of code in the interface file), it would be possible to have a function
|
||||
</p>
|
||||
<div class="code"><pre>
|
||||
double my_det(const double* mat, int m, int n);
|
||||
</pre></div>
|
||||
<p>
|
||||
that is accessed from Octave as,
|
||||
</p>
|
||||
<div class="targetlang"><pre>
|
||||
octave:1> my_det(rand(4));
|
||||
ans = -0.18388
|
||||
</pre></div>
|
||||
|
||||
<tt><br></tt>
|
||||
</body>
|
||||
</html>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue