Branch for development of -builtin option for python.
With this option, swig will produce new built-in python types for all wrapped classes. Built-in types offer a substantial performance benefit compared to the current shadow class implementation. git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/branches/szager-python-builtin@12331 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
commit
25a1f9844b
3883 changed files with 432049 additions and 0 deletions
11
.project
Normal file
11
.project
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>SWIG</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
34
ANNOUNCE
Normal file
34
ANNOUNCE
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
*** ANNOUNCE: SWIG 2.0.2 (in progress) ***
|
||||
|
||||
http://www.swig.org
|
||||
|
||||
We're pleased to announce SWIG-2.0.1, 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 languages including Perl, Python, Tcl, Ruby, PHP, Java,
|
||||
Scheme (Guile, MzScheme, CHICKEN), Ocaml, Lua, Pike, C#, Modula-3, Octave, R,
|
||||
Common Lisp (CLISP, Allegro CL, CFFI, UFFI). SWIG can also export its parse
|
||||
tree in the form of XML and Lisp s-expressions. Major applications of
|
||||
SWIG include generation of scripting language extension modules, rapid
|
||||
prototyping, testing, and user interface development for large C/C++
|
||||
systems.
|
||||
|
||||
Availability
|
||||
============
|
||||
The release is available for download on Sourceforge at
|
||||
|
||||
http://prdownloads.sourceforge.net/swig/swig-2.0.1.tar.gz
|
||||
|
||||
A Windows version is also available at
|
||||
|
||||
http://prdownloads.sourceforge.net/swig/swigwin-2.0.1.zip
|
||||
|
||||
Please report problems with this release to the swig-devel mailing list,
|
||||
details at http://www.swig.org/mail.html.
|
||||
|
||||
--- The SWIG Developers
|
||||
|
||||
339
CCache/COPYING
Normal file
339
CCache/COPYING
Normal file
|
|
@ -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.
|
||||
77
CCache/Makefile.in
Normal file
77
CCache/Makefile.in
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
datarootdir = @datarootdir@
|
||||
srcdir=@srcdir@
|
||||
VPATH=@srcdir@
|
||||
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
bindir=@bindir@
|
||||
mandir=@mandir@
|
||||
INSTALLCMD=@INSTALL@
|
||||
PACKAGE_NAME=@PACKAGE_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=../../Lib
|
||||
EXEEXT=@EXEEXT@
|
||||
|
||||
# Use standard autoconf approach to transform executable name using --program-prefix and --program-suffix
|
||||
transform = @program_transform_name@
|
||||
|
||||
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
|
||||
|
||||
all: $(PACKAGE_NAME)$(EXEEXT)
|
||||
|
||||
# Note that HTML documentation is actually generated and used from the main SWIG documentation Makefile
|
||||
docs: $(PACKAGE_NAME).1 web/ccache-man.html
|
||||
|
||||
$(PACKAGE_NAME)$(EXEEXT): $(OBJS) $(HEADERS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||
|
||||
$(PACKAGE_NAME).1: ccache.yo
|
||||
-yodl2man -o $(PACKAGE_NAME).1 ccache.yo
|
||||
|
||||
web/ccache-man.html: ccache.yo
|
||||
yodl2html -o web/ccache-man.html ccache.yo
|
||||
|
||||
install: $(PACKAGE_NAME)$(EXEEXT) $(PACKAGE_NAME).1
|
||||
@echo "Installing $(PACKAGE_NAME)"
|
||||
@echo "Installing $(DESTDIR)${bindir}/`echo $(PACKAGE_NAME) | sed '$(transform)'`$(EXEEXT)"
|
||||
${INSTALLCMD} -d $(DESTDIR)${bindir}
|
||||
${INSTALLCMD} -m 755 $(PACKAGE_NAME)$(EXEEXT) $(DESTDIR)${bindir}/`echo $(PACKAGE_NAME) | sed '$(transform)'`$(EXEEXT)
|
||||
@echo "Installing $(DESTDIR)${mandir}/man1/`echo $(PACKAGE_NAME) | sed '$(transform)'`.1"
|
||||
${INSTALLCMD} -d $(DESTDIR)${mandir}/man1
|
||||
${INSTALLCMD} -m 644 ${srcdir}/$(PACKAGE_NAME).1 $(DESTDIR)${mandir}/man1/`echo $(PACKAGE_NAME) | sed '$(transform)'`.1
|
||||
|
||||
uninstall: $(PACKAGE_NAME)$(EXEEXT) $(PACKAGE_NAME).1
|
||||
rm -f $(DESTDIR)${bindir}/`echo $(PACKAGE_NAME) | sed '$(transform)'`$(EXEEXT)
|
||||
rm -f $(DESTDIR)${mandir}/man1/`echo $(PACKAGE_NAME) | sed '$(transform)'`.1
|
||||
|
||||
clean:
|
||||
/bin/rm -f $(OBJS) *~ $(PACKAGE_NAME)$(EXEEXT)
|
||||
|
||||
check : test
|
||||
|
||||
test: test.sh
|
||||
SWIG_LIB='$(SWIG_LIB)' PATH=../..:$$PATH SWIG='$(SWIG)' CC='$(CC)' NOSOFTLINKSTEST='$(NOSOFTLINKSTEST)' ./test.sh
|
||||
|
||||
check: test
|
||||
|
||||
distclean: clean
|
||||
/bin/rm -f Makefile config.h config.sub config.log build-stamp config.status ccache_swig_config.h
|
||||
/bin/rm -rf autom4te.cache
|
||||
|
||||
maintainer-clean: distclean
|
||||
/bin/rm -f $(PACKAGE_NAME).1 web/ccache-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
|
||||
31
CCache/README
Normal file
31
CCache/README
Normal file
|
|
@ -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
|
||||
|
||||
8
CCache/README.swig
Normal file
8
CCache/README.swig
Normal file
|
|
@ -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.
|
||||
91
CCache/args.c
Normal file
91
CCache/args.c
Normal file
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
1388
CCache/ccache.c
Normal file
1388
CCache/ccache.c
Normal file
File diff suppressed because it is too large
Load diff
205
CCache/ccache.h
Normal file
205
CCache/ccache.h
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
#include "ccache_swig_config.h"
|
||||
|
||||
#define CCACHE_VERSION SWIG_VERSION
|
||||
|
||||
#ifndef _WIN32
|
||||
#include "config.h"
|
||||
#else
|
||||
#include <sys/locking.h>
|
||||
#define PACKAGE_NAME "ccache-swig.exe"
|
||||
#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
|
||||
#define _WIN32_WINNT 0x0500
|
||||
#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 PACKAGE_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);
|
||||
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 */
|
||||
#ifdef __CYGWIN__
|
||||
#undef HAVE_MKSTEMP
|
||||
#endif
|
||||
422
CCache/ccache.yo
Normal file
422
CCache/ccache.yo
Normal file
|
|
@ -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>
|
||||
|
||||
))
|
||||
1
CCache/ccache_swig_config.h.in
Normal file
1
CCache/ccache_swig_config.h.in
Normal file
|
|
@ -0,0 +1 @@
|
|||
#define SWIG_VERSION "@PACKAGE_VERSION@"
|
||||
193
CCache/cleanup.c
Normal file
193
CCache/cleanup.c
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
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(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (num_files > 1) {
|
||||
/* sort in ascending data order */
|
||||
qsort(files, num_files, sizeof(struct files *),
|
||||
(COMPAR_FN_T)files_compare);
|
||||
}
|
||||
|
||||
/* 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 (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)
|
||||
{
|
||||
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();
|
||||
|
||||
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]);
|
||||
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);
|
||||
}
|
||||
87
CCache/configure.in
Normal file
87
CCache/configure.in
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
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)
|
||||
|
||||
dnl Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_PROG_INSTALL
|
||||
AC_ARG_PROGRAM # for program_transform_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
|
||||
22
CCache/debian/NEWS
Normal file
22
CCache/debian/NEWS
Normal file
|
|
@ -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
|
||||
59
CCache/debian/README.Debian
Normal file
59
CCache/debian/README.Debian
Normal file
|
|
@ -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
|
||||
221
CCache/debian/changelog
Normal file
221
CCache/debian/changelog
Normal file
|
|
@ -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
|
||||
|
||||
1
CCache/debian/compat
Normal file
1
CCache/debian/compat
Normal file
|
|
@ -0,0 +1 @@
|
|||
6
|
||||
20
CCache/debian/control
Normal file
20
CCache/debian/control
Normal file
|
|
@ -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.
|
||||
29
CCache/debian/copyright
Normal file
29
CCache/debian/copyright
Normal file
|
|
@ -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.
|
||||
3
CCache/debian/dirs
Normal file
3
CCache/debian/dirs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
usr/bin
|
||||
usr/lib/ccache
|
||||
usr/share/man/man1
|
||||
1
CCache/debian/docs
Normal file
1
CCache/debian/docs
Normal file
|
|
@ -0,0 +1 @@
|
|||
README
|
||||
2
CCache/debian/examples
Normal file
2
CCache/debian/examples
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
debian/update-ccache
|
||||
manage-cache.sh
|
||||
100
CCache/debian/patches/01_no_home.diff
Normal file
100
CCache/debian/patches/01_no_home.diff
Normal file
|
|
@ -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;
|
||||
}
|
||||
|
||||
1026
CCache/debian/patches/02_ccache-compressed.diff
Normal file
1026
CCache/debian/patches/02_ccache-compressed.diff
Normal file
File diff suppressed because it is too large
Load diff
133
CCache/debian/patches/03_long_options.diff
Normal file
133
CCache/debian/patches/03_long_options.diff
Normal file
|
|
@ -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
|
||||
13
CCache/debian/patches/04_ignore_profile.diff
Normal file
13
CCache/debian/patches/04_ignore_profile.diff
Normal file
|
|
@ -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) {
|
||||
45
CCache/debian/patches/05_nfs_fix.diff
Normal file
45
CCache/debian/patches/05_nfs_fix.diff
Normal file
|
|
@ -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
|
||||
77
CCache/debian/patches/06_md.diff
Normal file
77
CCache/debian/patches/06_md.diff
Normal file
|
|
@ -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 */
|
||||
75
CCache/debian/patches/07_cachedirtag.diff
Normal file
75
CCache/debian/patches/07_cachedirtag.diff
Normal file
|
|
@ -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
|
||||
89
CCache/debian/patches/08_manpage_hyphens.diff
Normal file
89
CCache/debian/patches/08_manpage_hyphens.diff
Normal file
|
|
@ -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"
|
||||
11
CCache/debian/patches/09_respect_ldflags.diff
Normal file
11
CCache/debian/patches/09_respect_ldflags.diff
Normal file
|
|
@ -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
|
||||
23
CCache/debian/patches/10_lru_cleanup.diff
Normal file
23
CCache/debian/patches/10_lru_cleanup.diff
Normal file
|
|
@ -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) {
|
||||
85
CCache/debian/patches/11_utimes.diff
Normal file
85
CCache/debian/patches/11_utimes.diff
Normal file
|
|
@ -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(
|
||||
83
CCache/debian/patches/12_cachesize_permissions.diff
Normal file
83
CCache/debian/patches/12_cachesize_permissions.diff
Normal file
|
|
@ -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);
|
||||
33
CCache/debian/patches/13_html_links.diff
Normal file
33
CCache/debian/patches/13_html_links.diff
Normal file
|
|
@ -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:
|
||||
48
CCache/debian/patches/14_hardlink_doc.diff
Normal file
48
CCache/debian/patches/14_hardlink_doc.diff
Normal file
|
|
@ -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.
|
||||
47
CCache/debian/patches/CREDITS
Normal file
47
CCache/debian/patches/CREDITS
Normal file
|
|
@ -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
|
||||
141
CCache/debian/rules
Normal file
141
CCache/debian/rules
Normal file
|
|
@ -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
|
||||
43
CCache/debian/update-ccache
Normal file
43
CCache/debian/update-ccache
Normal file
|
|
@ -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
|
||||
2
CCache/debian/watch
Normal file
2
CCache/debian/watch
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
version=2
|
||||
http://samba.org/ftp/ccache/ccache-(.*)\.tar\.gz
|
||||
286
CCache/execute.c
Normal file
286
CCache/execute.c
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
/*
|
||||
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);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void display_execute_args(char **argv)
|
||||
{
|
||||
if (argv) {
|
||||
printf("ccache executing: ");
|
||||
while (*argv) {
|
||||
printf("%s ", *argv);
|
||||
++argv;
|
||||
}
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
80
CCache/hash.c
Normal file
80
CCache/hash.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
238
CCache/install-sh
Executable file
238
CCache/install-sh
Executable file
|
|
@ -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
|
||||
284
CCache/mdfour.c
Normal file
284
CCache/mdfour.c
Normal file
|
|
@ -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
|
||||
36
CCache/mdfour.h
Normal file
36
CCache/mdfour.h
Normal file
|
|
@ -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);
|
||||
|
||||
|
||||
|
||||
|
||||
5
CCache/packaging/README
Normal file
5
CCache/packaging/README
Normal file
|
|
@ -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
|
||||
37
CCache/packaging/ccache.spec
Normal file
37
CCache/packaging/ccache.spec
Normal file
|
|
@ -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
|
||||
962
CCache/snprintf.c
Normal file
962
CCache/snprintf.c
Normal file
|
|
@ -0,0 +1,962 @@
|
|||
/*
|
||||
* 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;
|
||||
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;
|
||||
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;
|
||||
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 */
|
||||
361
CCache/stats.c
Normal file
361
CCache/stats.c
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
/*
|
||||
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) 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]);
|
||||
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);
|
||||
}
|
||||
452
CCache/test.sh
Executable file
452
CCache/test.sh
Executable file
|
|
@ -0,0 +1,452 @@
|
|||
#!/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
|
||||
|
||||
CCACHE=../ccache-swig
|
||||
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
|
||||
rmdir 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
|
||||
rmdir 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
|
||||
cd $TESTDIR || exit 1
|
||||
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"
|
||||
ln -s $CCACHE $COMPILER
|
||||
CCACHE_COMPILE="./$COMPILER"
|
||||
basetests
|
||||
rm "./$COMPILER"
|
||||
ln -s $CCACHE $SWIG
|
||||
CCACHE_COMPILE="./$SWIG"
|
||||
swigtests
|
||||
rm "./$SWIG"
|
||||
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
|
||||
307
CCache/unify.c
Normal file
307
CCache/unify.c
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
/*
|
||||
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);
|
||||
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);
|
||||
if (map == (char *)-1) {
|
||||
cc_log("Failed to mmap %s\n", fname);
|
||||
stats_update(STATS_PREPROCESSOR);
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
/* pass it through the unifier */
|
||||
unify((unsigned char *)map, st.st_size);
|
||||
|
||||
munmap(map, st.st_size);
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
884
CCache/util.c
Normal file
884
CCache/util.c
Normal file
|
|
@ -0,0 +1,884 @@
|
|||
/*
|
||||
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 */
|
||||
static 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) {
|
||||
fatal("Failed to copy fd");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
gz_out = gzdopen(dup(fd_out), "wb");
|
||||
if (!gz_out) {
|
||||
gzclose(gz_in);
|
||||
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) {
|
||||
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
|
||||
158
CCache/web/index.html
Normal file
158
CCache/web/index.html
Normal file
|
|
@ -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>
|
||||
41
CHANGES.current
Normal file
41
CHANGES.current
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
This file contains 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.
|
||||
|
||||
Version 2.0.2 (in progress)
|
||||
===========================
|
||||
|
||||
2010-12-07: iant
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
Check that we are using a sufficiently new version of the
|
||||
6g or 8g Go compiler. If not, disable Go.
|
||||
|
||||
2010-12-06: wsfulton
|
||||
Fix #3127394 - use of network paths on Windows/MSys.
|
||||
|
||||
2010-11-18: klickverbot
|
||||
[D] Added the D language module.
|
||||
|
||||
2010-11-12: vadz
|
||||
Fix handling of multiple regex-using %renames attached to the same
|
||||
declaration. For example, now
|
||||
|
||||
%rename("%(regex/^Set(.*)/put\\1/)s") "";
|
||||
%rename("%(regex/^Get(.*)/get\\1/)s") "";
|
||||
|
||||
works as expected whereas before only the last anonymous rename was
|
||||
taken into account.
|
||||
|
||||
2010-10-17: drjoe
|
||||
[R] Fix failure in overloaded functions which was breaking
|
||||
QuantLib-SWIG
|
||||
|
||||
2010-10-14: olly
|
||||
[PHP] Allow compilation on non-conforming Microsoft C++ compilers
|
||||
which don't accept: return function_returning_void();
|
||||
Reported by Frank Vanden Berghen on the SWIG mailing list.
|
||||
|
||||
2010-10-12: wsfulton
|
||||
Fix unary scope operator (::) (global scope) regression introduced in 2.0.0, reported by
|
||||
Ben Walker. The mangled symbol names were incorrect, sometimes resulting in types being
|
||||
incorrectly treated as opaque types.
|
||||
101
COPYRIGHT
Normal file
101
COPYRIGHT
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
SWIG Copyright and Authors
|
||||
--------------------------
|
||||
|
||||
Copyright (c) 1995-2010 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)
|
||||
|
||||
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)
|
||||
Gonzalo Garramuno (ggarra@advancedsl.com.ar) (Ruby, Ruby's UTL)
|
||||
John Lenz (Guile, MzScheme updates, Chicken module, runtime system)
|
||||
Ian Lance Taylor (Go)
|
||||
Vadim Zeitlin (PCRE)
|
||||
|
||||
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
|
||||
(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.
|
||||
|
||||
79
Doc/Devel/cmdopt.html
Normal file
79
Doc/Devel/cmdopt.html
Normal file
|
|
@ -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>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
414
Doc/Devel/engineering.html
Normal file
414
Doc/Devel/engineering.html
Normal file
|
|
@ -0,0 +1,414 @@
|
|||
<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. SVN 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, license information and
|
||||
a SVN revision tag 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 ...
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
static char cvs[] = "$Id$";
|
||||
|
||||
#include "swig.h"
|
||||
|
||||
/* Declarations */
|
||||
typedef struct {
|
||||
int x, y;
|
||||
} Foo;
|
||||
|
||||
...
|
||||
|
||||
/* Private Declarations (used only in this file) */
|
||||
static int avariable;
|
||||
|
||||
...
|
||||
|
||||
/* Functions */
|
||||
...
|
||||
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
The SVN revision tag should be placed into a static string as shown
|
||||
above mangled with the name of the file.
|
||||
This adds the revision information to the SWIG executable and
|
||||
makes it possible to extract version information from a raw binary
|
||||
(sometimes useful in debugging).
|
||||
|
||||
<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. SVN Tagging Conventions</h2>
|
||||
</a>
|
||||
|
||||
Use <tt>svn 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 svn access.
|
||||
<ul>
|
||||
<li> Internal tags should start with the developer name and a hyphen.
|
||||
<li> External tags should start with "v-".
|
||||
</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> v-1-3-a37-fixes-bug-2432
|
||||
<li> v-1-3-a37-fixes-bug-2433
|
||||
<li> v-1-3-a37-fixes-bug-2432-again
|
||||
<li> v-1-3-a37-release
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
Copyright (C) 1999-2004 SWIG Development Team.
|
||||
</body>
|
||||
</html>
|
||||
181
Doc/Devel/file.html
Normal file
181
Doc/Devel/file.html
Normal file
|
|
@ -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>
|
||||
30
Doc/Devel/index.html
Normal file
30
Doc/Devel/index.html
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<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>.
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
Copyright (C) 1999-2007 SWIG Development Team.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
1186
Doc/Devel/internals.html
Normal file
1186
Doc/Devel/internals.html
Normal file
File diff suppressed because it is too large
Load diff
140
Doc/Devel/migrate.txt
Normal file
140
Doc/Devel/migrate.txt
Normal file
|
|
@ -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.
|
||||
|
||||
|
||||
102
Doc/Devel/parm.html
Normal file
102
Doc/Devel/parm.html
Normal file
|
|
@ -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>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
169
Doc/Devel/runtime.txt
Normal file
169
Doc/Devel/runtime.txt
Normal file
|
|
@ -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
|
||||
(like the chicken module), 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
|
||||
(C_word in chicken, 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);
|
||||
}
|
||||
283
Doc/Devel/scanner.html
Normal file
283
Doc/Devel/scanner.html
Normal file
|
|
@ -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>
|
||||
284
Doc/Devel/tree.html
Normal file
284
Doc/Devel/tree.html
Normal file
|
|
@ -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 it's 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 thats 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>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
223
Doc/Devel/wrapobj.html
Normal file
223
Doc/Devel/wrapobj.html
Normal file
|
|
@ -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>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
2150
Doc/Manual/Allegrocl.html
Normal file
2150
Doc/Manual/Allegrocl.html
Normal file
File diff suppressed because it is too large
Load diff
496
Doc/Manual/Arguments.html
Normal file
496
Doc/Manual/Arguments.html
Normal file
|
|
@ -0,0 +1,496 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Argument Handling</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<H1><a name="Arguments"></a>9 Argument Handling</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 3, 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"></a>9.1 The typemaps.i library</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"></a>9.1.1 Introduction</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"></a>9.1.2 Input parameters</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"></a>9.1.3 Output parameters</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"></a>9.1.4 Input/Output parameters</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"></a>9.1.5 Using different names</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"></a>9.2 Applying constraints to input values</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"></a>9.2.1 Simple constraint example</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"></a>9.2.2 Constraint methods</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"></a>9.2.3 Applying constraints to new datatypes</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>
|
||||
2438
Doc/Manual/CSharp.html
Normal file
2438
Doc/Manual/CSharp.html
Normal file
File diff suppressed because it is too large
Load diff
597
Doc/Manual/Chicken.html
Normal file
597
Doc/Manual/Chicken.html
Normal file
|
|
@ -0,0 +1,597 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<!-- Hand-written HTML -->
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and Chicken</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
|
||||
<H1><a name="Chicken"></a>19 SWIG and Chicken</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"></a>19.1 Preliminaries</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"></a>19.1.1 Running SWIG in C mode</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"></a>19.1.2 Running SWIG in C++ mode</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"></a>19.2 Code Generation</H2>
|
||||
|
||||
|
||||
<H3><a name="Chicken_nn6"></a>19.2.1 Naming Conventions</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"></a>19.2.2 Modules</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"></a>19.2.3 Constants and Variables</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"></a>19.2.4 Functions</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"></a>19.2.5 Exceptions</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"></a>19.3 TinyCLOS</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"></a>19.4 Linkage</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"></a>19.4.1 Static binary or shared library linked at compile time</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"></a>19.4.2 Building chicken extension libraries</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"></a>19.4.3 Linking multiple SWIG modules with TinyCLOS</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"></a>19.5 Typemaps</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"></a>19.6 Pointers</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"></a>19.6.1 Garbage collection</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"></a>19.7 Unsupported features and known problems</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"></a>19.7.1 TinyCLOS problems with Chicken version <= 1.92</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>
|
||||
1650
Doc/Manual/Contents.html
Normal file
1650
Doc/Manual/Contents.html
Normal file
File diff suppressed because it is too large
Load diff
274
Doc/Manual/Contract.html
Normal file
274
Doc/Manual/Contract.html
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Contract Checking</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<H1><a name="Contract"></a>12 Contracts</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"></a>12.1 The %contract directive</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"></a>12.2 %contract and classes</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"></a>12.3 Constant aggregation and %aggregate_check</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"></a>12.4 Notes</H2>
|
||||
|
||||
|
||||
<p>
|
||||
Contract support was implemented by Songyan (Tiger) Feng and first appeared
|
||||
in SWIG-1.3.20.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
1162
Doc/Manual/Customization.html
Normal file
1162
Doc/Manual/Customization.html
Normal file
File diff suppressed because it is too large
Load diff
430
Doc/Manual/D.html
Normal file
430
Doc/Manual/D.html
Normal file
|
|
@ -0,0 +1,430 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<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"></a>20 SWIG and D</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"><tt>%feature</tt>s</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_native_pointer_support">Native pointer support</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"></a>20.1 Introduction</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">C#</a> (and also on <a href="Java.html">Java</a>, since the C# module was in turn forked from it).</p>
|
||||
|
||||
|
||||
<H2><a name="D_command_line_invocation"></a>20.2 Command line invocation</H2>
|
||||
|
||||
|
||||
<p>To activate the D module, pass the <tt>-d</tt> option to SWIG at the command line. The same standard command line switches 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 id="D_splitproxy"><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 switch), 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 switch 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 switch, 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"></a>20.3 Typemaps</H2>
|
||||
|
||||
|
||||
<H3><a name="D_typemap_name_comparison"></a>20.3.1 C# <-> D name comparison</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
|
||||
csdestruct <-> ddispose
|
||||
csdestruct_derived <-> ddispose_derived
|
||||
</pre></div>
|
||||
|
||||
|
||||
<H3><a name="D_ctype_imtype_dtype"></a>20.3.2 ctype, imtype, dtype</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"></a>20.3.3 in, out, directorin, directorout</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"></a>20.3.4 din, dout, ddirectorin, ddirectorout</H3>
|
||||
|
||||
|
||||
<p>Typemaps for code generation in D proxy and type wrapper classes.</p>
|
||||
|
||||
<p id="D_din">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"><tt>$dinput</tt></a> macro is replaced).</p>
|
||||
|
||||
<p id="D_dout">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_wcall"><tt>$imcall</tt> and <tt>$owner</tt></a> macros are replaced).</p>
|
||||
|
||||
<p id="D_ddirectorinout">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"></a>20.3.5 typecheck typemaps</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"></a>20.3.6 Code injection typemaps</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 id="D_class_code_typemaps"><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>
|
||||
|
||||
|
||||
<H3><a name="D_special_variables"></a>20.3.7 Special variable macros</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>$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 id="D_dinput"><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 id="D_wcall"><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 id="D_dpcall"><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 id="D_importtype"><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 it 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"></a>20.4 <tt>%feature</tt>s</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"></a>20.5 Pragmas</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>, 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"></a>20.6 D Exceptions</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"></a>20.7 D Directors</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"></a>20.8 Other features</H2>
|
||||
|
||||
|
||||
<p>The <a href="SWIGPlus.html#SWIGPlus_nspace"><tt>nspace</tt></a> feature of SWIG is not yet supported for D – all class modules are written to the same package, regardless of which C++ namespace they are in.</p>
|
||||
|
||||
|
||||
<H3><a name="D_native_pointer_support"></a>20.8.1 Native pointer support</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 »primtive type« 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_test_suite"></a>20.8.2 Running the test-suite</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"></a>20.9 D Typemap examples</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"></a>20.10 Work in progress and planned features</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>
|
||||
<li><em>Operator overloading:</em> Currently, operator overloading is supported only to a very limited extent – many C++ operators are just ignored with a warning. The problem here is that the way D handles operator overloading differs quite a lot from the way C++ does it, both syntactically and semantically, and even more so since the advent of template-based operator overloading in D2.</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>
|
||||
|
||||
4057
Doc/Manual/Extending.html
Normal file
4057
Doc/Manual/Extending.html
Normal file
File diff suppressed because it is too large
Load diff
454
Doc/Manual/Go.html
Normal file
454
Doc/Manual/Go.html
Normal file
|
|
@ -0,0 +1,454 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and Go</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF">
|
||||
<H1><a name="Go"></a>20 SWIG and Go</H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#Go_overview">Overview</a>
|
||||
<li><a href="#Go_running_swig">Running SWIG with Go</a>
|
||||
<ul>
|
||||
<li><a href="#Go_commandline">Additional Commandline Options</a>
|
||||
<li><a href="#Go_outputs">Go Output Files</a>
|
||||
</ul>
|
||||
<li><a href="#Go_basic_tour">A tour of basic C/C++ wrapping</a>
|
||||
<ul>
|
||||
<li><a href="#Go_package">Go Package Name</a>
|
||||
<li><a href="#Go_names">Go Names</a>
|
||||
<li><a href="#Go_constants">Go Constants</a>
|
||||
<li><a href="#Go_enumerations">Go Enumerations</a>
|
||||
<li><a href="#Go_classes">Go Classes</a>
|
||||
<ul>
|
||||
<li><a href="#Go_class_inheritance">Go Class Inheritance</a>
|
||||
</ul>
|
||||
<li><a href="#Go_templates">Go Templates</a>
|
||||
<li><a href="#Go_director_classes">Go Director Classes</a>
|
||||
<li><a href="#Go_primitive_type_mappings">Default Go primitive type mappings</a>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
This chapter describes SWIG's support of Go. For more information on
|
||||
the Go programming language
|
||||
see <a href="http://golang.org/">golang.org</a>.
|
||||
</p>
|
||||
|
||||
<H2><a name="Go_overview"></a>20.1 Overview</H2>
|
||||
|
||||
|
||||
<p>
|
||||
Go is a compiled language, not a scripting language. However, it does
|
||||
not support direct calling of functions written in C/C++. The cgo
|
||||
program may be used to generate wrappers to call C code from Go, but
|
||||
there is no convenient way to call C++ code. SWIG fills this gap.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
There are (at least) two different Go compilers. One is the gc
|
||||
compiler, normally invoked under the names 6g, 8g, or 5g. The other
|
||||
is the gccgo compiler, which is a frontend to the gcc compiler suite.
|
||||
The interface to C/C++ code is completely different for the two Go
|
||||
compilers. SWIG supports both, selected by a command line option.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Because Go is a type-safe compiled language, SWIG's runtime type
|
||||
checking and runtime library are not used with Go. This should be
|
||||
borne in mind when reading the rest of the SWIG documentation.
|
||||
</p>
|
||||
|
||||
<H2><a name="Go_running_swig"></a>20.2 Running SWIG with Go</H2>
|
||||
|
||||
|
||||
<p>
|
||||
To generate Go code, use the <tt>-go</tt> option with SWIG. By
|
||||
default SWIG will generate code for the gc compilers. To generate
|
||||
code for gccgo, you should also use the <tt>-gccgo</tt> option.
|
||||
</p>
|
||||
|
||||
<H3><a name="Go_commandline"></a>20.2.1 Additional Commandline Options</H3>
|
||||
|
||||
|
||||
<p>
|
||||
These are the command line options for SWIG's GO module. They can
|
||||
also be seen by using:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
swig -go -help
|
||||
</pre></div>
|
||||
|
||||
<table summary="Go specific options">
|
||||
<tr>
|
||||
<th>Go specific options</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-gccgo</td>
|
||||
<td>Generate code for gccgo. The default is to generate code for
|
||||
6g/8g/6g.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-package <name></td>
|
||||
<td>Set the name of the Go package to <name>. The default
|
||||
package name is the SWIG module name.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-go-prefix <prefix></td>
|
||||
<td>When generating code for gccgo, set the prefix to use. This
|
||||
corresponds to the <tt>-fgo-prefix</tt> option to gccgo.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-long-type-size <s></td>
|
||||
<td>Set the size for the C/C++ type <tt>long</tt>. This controls
|
||||
whether <tt>long</tt> is converted to the Go type <tt>int32</tt>
|
||||
or <tt>int64</tt>. The <s> argument should be 32 or 64.</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<H3><a name="Go_outputs"></a>20.2.2 Go Output Files</H3>
|
||||
|
||||
|
||||
<p> When generating Go code, SWIG will generate the following
|
||||
files:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
MODULE.go will contain the Go functions that your Go code will call.
|
||||
These functions will be wrappers for the C++ functions defined by your
|
||||
module. This file should, of course, be compiled with the Go
|
||||
compiler.
|
||||
<li>
|
||||
MODULE_wrap.c or MODULE_wrap.cxx will contain C/C++ functions will be
|
||||
invoked by the Go wrapper code. This file should be compiled with the
|
||||
usual C or C++ compiler and linked into a shared library.
|
||||
<li>
|
||||
MODULE_wrap.h will be generated if you use the directors feature. It
|
||||
provides a definition of the generated C++ director classes. It is
|
||||
generally not necessary to use this file, but in some special cases it
|
||||
may be helpful to include it in your code, compiled with the usual C
|
||||
or C++ compiler.
|
||||
<li>
|
||||
If using the gc compiler, MODULE_gc.c will contain C code which should
|
||||
be compiled with the C compiler distributed as part of the gc compiler: 6c, 8c,
|
||||
or 5c. It should then be combined with the compiled MODULE.go using
|
||||
gopack. This file will not be generated when using gccgo.
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
A typical command sequence would look like this:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
% swig -go example.i
|
||||
% gcc -c -fpic example.c
|
||||
% gcc -c -fpic example_wrap.c
|
||||
% gcc -shared example.o example_wrap.o -o example.so
|
||||
% 6g example.go
|
||||
% 6c example_gc.c
|
||||
% gopack grc example.a example.6 example_gc.6
|
||||
% 6g main.go # your code, not generated by SWIG
|
||||
% 6l main.6
|
||||
</pre></div>
|
||||
|
||||
<H2><a name="Go_basic_tour"></a>20.3 A tour of basic C/C++ wrapping</H2>
|
||||
|
||||
|
||||
<p>
|
||||
By default, SWIG attempts to build a natural Go interface to your
|
||||
C/C++ code. However, the languages are somewhat different, so some
|
||||
modifications have to occur. This section briefly covers the
|
||||
essential aspects of this wrapping.
|
||||
</p>
|
||||
|
||||
<H3><a name="Go_package"></a>20.3.1 Go Package Name</H3>
|
||||
|
||||
|
||||
<p>
|
||||
All Go source code lives in a package. The name of this package will
|
||||
default to the name of the module from SWIG's <tt>%module</tt>
|
||||
directive. You may override this by using SWIG's <tt>-package</tt>
|
||||
command line option.
|
||||
</p>
|
||||
|
||||
<H3><a name="Go_names"></a>20.3.2 Go Names</H3>
|
||||
|
||||
|
||||
<p>
|
||||
In Go, a function is only visible outside the current package if the
|
||||
first letter of the name is uppercase. This is quite different from
|
||||
C/C++. Because of this, C/C++ names are modified when generating the
|
||||
Go interface: the first letter is forced to be uppercase if it is not
|
||||
already. This affects the names of functions, methods, variables,
|
||||
constants, enums, and classes.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
C/C++ variables are wrapped with setter and getter functions in Go.
|
||||
First the first letter of the variable name will be forced to
|
||||
uppercase, and then <tt>Get</tt> or <tt>Set</tt> will be prepended.
|
||||
For example, if the C/C++ variable is called <tt>var</tt>, then SWIG
|
||||
will define the functions <tt>GetVar</tt> and <tt>SetVar</tt>. If a
|
||||
variable is declared as <tt>const</tt>, or if
|
||||
SWIG's <a href="SWIG.html#SWIG_readonly_variables">
|
||||
<tt>%immutable</tt> directive</a> is used for the variable, then only
|
||||
the getter will be defined.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
C++ classes will be discussed further below. Here we'll note that the
|
||||
first letter of the class name will be forced to uppercase to give the
|
||||
name of a type in Go. A constructor will be named <tt>New</tt>
|
||||
followed by that name, and the destructor will be
|
||||
named <tt>Delete</tt> followed by that name.
|
||||
</p>
|
||||
|
||||
<H3><a name="Go_constants"></a>20.3.3 Go Constants</H3>
|
||||
|
||||
|
||||
<p>
|
||||
C/C++ constants created via <tt>#define</tt> or the <tt>%constant</tt>
|
||||
directive become Go constants, declared with a <tt>const</tt>
|
||||
declaration.
|
||||
|
||||
<H3><a name="Go_enumerations"></a>20.3.4 Go Enumerations</H3>
|
||||
|
||||
|
||||
<p>
|
||||
C/C++ enumeration types will cause SWIG to define an integer type with
|
||||
the name of the enumeration (with first letter forced to uppercase as
|
||||
usual). The values of the enumeration will become variables in Go;
|
||||
code should avoid modifying those variables.
|
||||
</p>
|
||||
|
||||
<H3><a name="Go_classes"></a>20.3.5 Go Classes</H3>
|
||||
|
||||
|
||||
<p>
|
||||
Go has interfaces, methods and inheritance, but it does not have
|
||||
classes in the same sense as C++. This sections describes how SWIG
|
||||
represents C++ classes represented in Go.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For a C++ class <tt>ClassName</tt>, SWIG will define two types in Go:
|
||||
an underlying type, which will just hold a pointer to the C++ type,
|
||||
and an interface type. The interface type will be
|
||||
named <tt>ClassName</tt>. SWIG will define a
|
||||
function <tt>NewClassName</tt> which will take any constructor
|
||||
arguments and return a value of the interface
|
||||
type <tt>ClassName</tt>. SWIG will also define a
|
||||
destructor <tt>DeleteClassName</tt>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
SWIG will represent any methods of the C++ class as methods on the
|
||||
underlying type, and also as methods of the interface type. Thus C++
|
||||
methods may be invoked directly using the
|
||||
usual <tt>val.MethodName</tt> syntax. Public members of the C++ class
|
||||
will be given getter and setter functions defined as methods of the
|
||||
class.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
SWIG will represent static methods of C++ classes as ordinary Go
|
||||
functions. SWIG will use names like <tt>ClassName_MethodName</tt>.
|
||||
SWIG will give static members getter and setter functions with names
|
||||
like <tt>GetClassName_VarName</tt>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Given a value of the interface type, Go code can retrieve the pointer
|
||||
to the C++ type by calling the <tt>Swigcptr</tt> method. This will
|
||||
return a value of type <tt>SwigcptrClassName</tt>, which is just a
|
||||
name for <tt>uintptr</tt>. A Go type conversion can be used to
|
||||
convert this value to a different C++ type, but note that this
|
||||
conversion will not be type checked and is essentially equivalent
|
||||
to <tt>reinterpret_cast</tt>. This should only be used for very
|
||||
special cases, such as where C++ would use a <tt>dynamic_cast</tt>.
|
||||
</p>
|
||||
|
||||
<H4><a name="Go_class_inheritance"></a>20.3.5.1 Go Class Inheritance</H4>
|
||||
|
||||
|
||||
<p>
|
||||
C++ class inheritance is automatically represented in Go due to its
|
||||
use of interfaces. The interface for a child class will be a superset
|
||||
of the interface of its parent class. Thus a value of the child class
|
||||
type in Go may be passed to a function which expects the parent class.
|
||||
Doing the reverse will require an explicit type assertion, which will
|
||||
be checked dynamically.
|
||||
</p>
|
||||
|
||||
<H3><a name="Go_templates"></a>20.3.6 Go Templates</H3>
|
||||
|
||||
|
||||
<p>
|
||||
In order to use C++ templates in Go, you must tell SWIG to create
|
||||
wrappers for a particular template instantation. To do this, use
|
||||
the <tt>%template</tt> directive.
|
||||
|
||||
<H3><a name="Go_director_classes"></a>20.3.7 Go Director Classes</H3>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG's director feature permits a Go type to act as the subclass of a
|
||||
C++ class with virtual methods. This is complicated by the fact that
|
||||
C++ and Go define inheritance differently. In Go, structs can inherit
|
||||
methods via anonymous field embedding. However, when a method is
|
||||
called for an embedded struct, if that method calls any other methods,
|
||||
they are called for the embedded struct, not for the original type.
|
||||
Therefore, SWIG must use Go interfaces to represent C++ inheritance.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In order to use the director feature in Go, you must define a type in
|
||||
your Go code. You must then add methods for the type. Define a
|
||||
method in Go for each C++ virtual function that you want to override.
|
||||
You must then create a value of your new type, and pass a pointer to
|
||||
it to the function <tt>NewDirectorClassName</tt>,
|
||||
where <tt>ClassName</tt> is the name of the C++ class. That will
|
||||
return a value of type <tt>ClassName</tt>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
type GoClass struct { }
|
||||
func (p *GoClass) VirtualFunction() { }
|
||||
func MakeClass() ClassName {
|
||||
return NewDirectorClassName(&GoClass{})
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Any call in C++ code to the virtual function will wind up calling the
|
||||
method defined in Go. The Go code may of course call other methods on
|
||||
itself, and those methods may be defined either in Go or in C++.
|
||||
</p>
|
||||
|
||||
<H3><a name="Go_primitive_type_mappings"></a>20.3.8 Default Go primitive type mappings</H3>
|
||||
|
||||
|
||||
<p>
|
||||
The following table lists the default type mapping from C/C++ to Go.
|
||||
This table will tell you which Go type to expect for a function which
|
||||
uses a given C/C++ type.
|
||||
</p>
|
||||
|
||||
<table BORDER summary="Go primitive type mappings">
|
||||
<tr>
|
||||
<td><b>C/C++ type</b></td>
|
||||
<td><b>Go type</b></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>bool</td>
|
||||
<td>bool</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>char</td>
|
||||
<td>byte</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>signed char</td>
|
||||
<td>int8</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>unsigned char</td>
|
||||
<td>byte</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>short</td>
|
||||
<td>int16</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>unsigned short</td>
|
||||
<td>uint16</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>int</td>
|
||||
<td>int</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>unsigned int</td>
|
||||
<td>uint</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>long</td>
|
||||
<td>int32 or int64, depending on <tt>-long-type-size</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>unsigned long</td>
|
||||
<td>uint32 or uint64, depending on <tt>-long-type-size</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>long long</td>
|
||||
<td>int64</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>unsigned long long</td>
|
||||
<td>uint64</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>float</td>
|
||||
<td>float32</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>double</td>
|
||||
<td>float64</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>char *<br>char []</td>
|
||||
<td>string</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<p>
|
||||
Note that SWIG wraps the C <tt>char</tt> type as a character. Pointers
|
||||
and arrays of this type are wrapped as strings. The <tt>signed
|
||||
char</tt> type can be used if you want to treat <tt>char</tt> as a
|
||||
signed number rather than a character. Also note that all const
|
||||
references to primitive types are treated as if they are passed by
|
||||
value.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
These type mappings are defined by the "gotype" typemap. You may change
|
||||
that typemap, or add new values, to control how C/C++ types are mapped
|
||||
into Go types.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
893
Doc/Manual/Guile.html
Normal file
893
Doc/Manual/Guile.html
Normal file
|
|
@ -0,0 +1,893 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<!-- Hand-written HTML -->
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and Guile</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
|
||||
<H1><a name="Guile"></a>21 SWIG and Guile</H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#Guile_nn2">Meaning of "Module"</a>
|
||||
<li><a href="#Guile_nn3">Using the SCM or 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_nn13">GH Smobs</a>
|
||||
<li><a href="#Guile_nn14">SCM Smobs</a>
|
||||
<li><a href="#Guile_nn15">Garbage Collection</a>
|
||||
</ul>
|
||||
<li><a href="#Guile_nn16">Exception Handling</a>
|
||||
<li><a href="#Guile_nn17">Procedure documentation</a>
|
||||
<li><a href="#Guile_nn18">Procedures with setters</a>
|
||||
<li><a href="#Guile_nn19">GOOPS Proxy Classes</a>
|
||||
<ul>
|
||||
<li><a href="#Guile_nn20">Naming Issues</a>
|
||||
<li><a href="#Guile_nn21">Linking</a>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
This section details guile-specific support in SWIG.
|
||||
|
||||
<H2><a name="Guile_nn2"></a>21.1 Meaning of "Module"</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"></a>21.2 Using the SCM or GH Guile API</H2>
|
||||
|
||||
|
||||
<p>The guile module can currently export wrapper files that use the guile GH interface or the
|
||||
SCM interface. This is controlled by an argument passed to swig. The "-gh" argument causes swig
|
||||
to output GH code, and the "-scm" argument causes swig to output SCM code. Right now the "-scm" argument
|
||||
is the default. The "-scm" wrapper generation assumes a guile version >= 1.6 and has several advantages over
|
||||
the "-gh" wrapper generation including garbage collection and GOOPS support.
|
||||
The "-gh" wrapper generation can be used for older versions of guile.
|
||||
The guile GH wrapper code generation is depreciated and the
|
||||
SCM interface is the default. The SCM and GH interface differ greatly in how they store
|
||||
pointers and have completely different run-time code. See below for more info.
|
||||
|
||||
<p>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>.
|
||||
The idea of the GH interface was to provide a high level API that other languages and projects
|
||||
could adopt. This was a good idea, but didn't pan out well for general development. But for the
|
||||
specific, minimal uses that the SWIG typemaps put the GH interface to use is ideal for
|
||||
using a high level API. So even though the GH interface is depreciated, SWIG will continue to use
|
||||
the GH interface and provide mappings from the GH interface to whatever API we need.
|
||||
We can maintain this mapping where guile failed because SWIG uses a small subset of all the GH functions
|
||||
which map easily. All the guile typemaps like typemaps.i and std_vector.i
|
||||
will continue to use the GH functions to do things like create lists of values, convert strings to
|
||||
integers, etc. Then every language module will define a mapping between the GH interface and
|
||||
whatever custom API the language uses. This is currently implemented by the guile module to use
|
||||
the SCM guile API rather than the GH guile API.
|
||||
For example, here are some of the current mapping file for the SCM API</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
|
||||
#define gh_append2(a, b) scm_append(scm_listify(a, b, SCM_UNDEFINED))
|
||||
#define gh_apply(a, b) scm_apply(a, b, SCM_EOL)
|
||||
#define gh_bool2scm SCM_BOOL
|
||||
#define gh_boolean_p SCM_BOOLP
|
||||
#define gh_car SCM_CAR
|
||||
#define gh_cdr SCM_CDR
|
||||
#define gh_cons scm_cons
|
||||
#define gh_double2scm scm_make_real
|
||||
...
|
||||
</pre></div>
|
||||
|
||||
<p>This file is parsed by SWIG at wrapper generation time, so every reference to a gh_ function is replaced
|
||||
by a scm_ function in the wrapper file. Thus the gh_ function calls will never be seen in the wrapper;
|
||||
the wrapper will look exactly like it was generated
|
||||
for the specific API. Currently only the guile language module has created a mapping policy from gh_ to scm_,
|
||||
but there is no reason other languages (like mzscheme or chicken) couldn't also use this.
|
||||
If that happens, there is A LOT less code duplication in the standard typemaps.</p>
|
||||
|
||||
<H2><a name="Guile_nn4"></a>21.3 Linkage</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"></a>21.3.1 Simple Linkage</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 "./example.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 "./example.so" "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 "./example.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"></a>21.3.2 Passive Linkage</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"></a>21.3.3 Native Guile Module Linkage</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. This requires Guile 1.5.0 or later.
|
||||
|
||||
<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 "./foo.so"))
|
||||
;; 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 "./foo.so" "scm_init_my_modules_foo_module")
|
||||
</pre>
|
||||
</div>
|
||||
</ul>
|
||||
|
||||
<H3><a name="Guile_nn8"></a>21.3.4 Old Auto-Loading Guile Module Linkage</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"></a>21.3.5 Hobbit4D Linkage</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"></a>21.4 Underscore Folding</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"></a>21.5 Typemaps</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"></a>21.6 Representation of pointers as smobs</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#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_nn13"></a>21.6.1 GH Smobs</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> A smob is a cons cell where the lower half of the CAR contains the smob type
|
||||
tag, while the upper half of the CAR and the whole CDR are available. Every
|
||||
module creates its own smob type in the clientdata field of the module. So the
|
||||
lower 16 bits of the car of the smob store the tag and the upper 16 bits store
|
||||
the index this type is in the array. We can then, given a smob, find its
|
||||
swig_type_info struct by using the tag (lower 16 bits of car) to find which
|
||||
module this type is in (since each tag is unique for the module). Then we use
|
||||
the upper 16 bits to index into the array of types attached to this module.
|
||||
Looking up the module from the tag is worst case O(# of modules) but average
|
||||
case O(1). This is because the modules are stored in a circularly linked list,
|
||||
and when we start searching the modules for the tag, we start looking with the
|
||||
module that the function doing the lookup is in. SWIG_Guile_ConvertPtr() takes
|
||||
as its first argument the swig_module_info * of the calling function, which is
|
||||
where we start comparing tags. Most types will be looked up in the same module
|
||||
that created them, so the first module we check will most likely be correct.
|
||||
Once we have a swig_type_info structure, we loop through the linked list of
|
||||
casts, using pointer comparisons.</p>
|
||||
|
||||
<H3><a name="Guile_nn14"></a>21.6.2 SCM Smobs</H3>
|
||||
|
||||
|
||||
<p>The SCM interface (using the "-scm" argument to swig) uses swigrun.swg.
|
||||
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. This is a lot easier than the GH interface above because we can store
|
||||
a pointer to the type info structure right in the type. With the GH interface, there was not enough
|
||||
room in the smob to store two whole words of data so we needed to store part of the "swig_type_info address"
|
||||
in the smob tag. If a generated GOOPS module has been loaded, smobs will be wrapped by the corresponding
|
||||
GOOPS class.</p>
|
||||
|
||||
|
||||
<H3><a name="Guile_nn15"></a>21.6.3 Garbage Collection</H3>
|
||||
|
||||
|
||||
<p>Garbage collection is a feature of the new SCM interface, and it is automatically included
|
||||
if you pass the "-scm" flag to swig. Thus the swig garbage collection support requires guile >1.6.
|
||||
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"></a>21.7 Exception Handling</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_nn17"></a>21.8 Procedure documentation</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>. You need Guile 1.4
|
||||
or later to make use of the documentation files.
|
||||
|
||||
<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_nn18"></a>21.9 Procedures with setters</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_nn19"></a>21.10 GOOPS Proxy Classes</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>GOOPS support is
|
||||
only available with the new SCM interface (enabled with the
|
||||
<code>-scm</code> command-line option of SWIG). 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_nn20"></a>21.10.1 Naming Issues</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_nn21"></a>21.10.2 Linking</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 .so library.
|
||||
|
||||
<div class="code"><pre>
|
||||
%goops %{ (load-extension "./foo.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 "./foo.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 <code>.so</code> 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 "./foo.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 "./foo.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 "./foo.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>
|
||||
463
Doc/Manual/Introduction.html
Normal file
463
Doc/Manual/Introduction.html
Normal file
|
|
@ -0,0 +1,463 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Introduction</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<H1><a name="Introduction"></a>2 Introduction</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_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"></a>2.1 What is SWIG?</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
|
||||
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 a 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"></a>2.2 Why use SWIG?</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 overflow 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_nn4"></a>2.3 A SWIG example</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"></a>2.3.1 SWIG interface file</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 ANSI 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"></a>2.3.2 The swig command</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"></a>2.3.3 Building a Perl5 module</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"></a>2.3.4 Building a Python module</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"></a>2.3.5 Shortcuts</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"></a>2.4 Supported C/C++ language features</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 ANSI 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>
|
||||
Currently, the only major C++ feature not supported is nested classes--a limitation
|
||||
that should be removed in a future release, but has some workarounds for the moment.
|
||||
</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 handle C++ code that
|
||||
stresses the very limits of many C++ compilers.
|
||||
|
||||
|
||||
<H2><a name="Introduction_nn11"></a>2.5 Non-intrusive interface building</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"></a>2.6 Incorporating SWIG into a build system</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="http://www.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 also can generate the custom commands necessary for
|
||||
driving SWIG from IDE's 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"></a>2.7 Hands off code generation</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"></a>2.8 SWIG and freedom</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 it's core, SWIG
|
||||
tries to distill even the most advanced C++ code down to a small
|
||||
well-defined set of interface building techniques based on ANSI 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.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
7795
Doc/Manual/Java.html
Normal file
7795
Doc/Manual/Java.html
Normal file
File diff suppressed because it is too large
Load diff
1894
Doc/Manual/Library.html
Normal file
1894
Doc/Manual/Library.html
Normal file
File diff suppressed because it is too large
Load diff
802
Doc/Manual/Lisp.html
Normal file
802
Doc/Manual/Lisp.html
Normal file
|
|
@ -0,0 +1,802 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and Common Lisp</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<H1><a name="Lisp"></a>23 SWIG and Common Lisp</H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#Lisp_nn2">Allegro Common Lisp</a>
|
||||
<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>
|
||||
<li><a href="#Lisp_nn8">CLISP</a>
|
||||
<ul>
|
||||
<li><a href="#Lisp_nn9">Additional Commandline Options </a>
|
||||
<li><a href="#Lisp_nn10">Details on CLISP bindings</a>
|
||||
</ul>
|
||||
<li><a href="#Lisp_nn11">UFFI </a>
|
||||
</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 only the Allegro Common
|
||||
Lisp, Common Foreign Function Interface(CFFI), CLisp and UFFI
|
||||
foreign function interfaces.
|
||||
</p>
|
||||
<H2><a name="Lisp_nn2"></a>23.1 Allegro Common Lisp</H2>
|
||||
|
||||
|
||||
<p>
|
||||
Allegro Common Lisp support in SWIG has been updated to include
|
||||
support for both C and C++. You can read about the interface
|
||||
<a href="Allegrocl.html#Allegrocl">here</a>
|
||||
</p>
|
||||
|
||||
<H2><a name="Lisp_nn3"></a>23.2 Common Foreign Function Interface(CFFI)</H2>
|
||||
|
||||
|
||||
<p>
|
||||
CFFI, the Common Foreign Function Interface, is a portable foreign
|
||||
function interface for ANSI Common Lisp systems, similar in
|
||||
spirit to UFFI. Unlike UFFI, 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"></a>23.2.1 Additional Commandline Options </H3>
|
||||
|
||||
|
||||
<p>
|
||||
The following table list the additional commandline options available for the CLISP module. They can also be seen by using:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
swig -cffi -help
|
||||
</pre></div>
|
||||
<br/>
|
||||
|
||||
<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"></a>23.2.2 Generating CFFI bindings</H3>
|
||||
|
||||
|
||||
As we mentioned earlier the ideal way to use SWIG is to use interface
|
||||
files. To illustrate the use of it, lets assume that we have a
|
||||
file named <i>test.h</i> with the following C code:
|
||||
|
||||
<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>
|
||||
|
||||
Corresponding to this we will write a simple interface file:
|
||||
<div class="code"><pre>
|
||||
%module test
|
||||
|
||||
%include "test.h"
|
||||
|
||||
</pre></div>
|
||||
|
||||
The generated SWIG Code will be:
|
||||
|
||||
<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;
|
||||
%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. 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))
|
||||
|
||||
(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"></a>23.2.3 Generating CFFI bindings for C++ code</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>
|
||||
Various features which were available for C headers can also be used
|
||||
here. The target header which we are going to use here is:
|
||||
<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>
|
||||
|
||||
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:
|
||||
<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>
|
||||
|
||||
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
|
||||
|
||||
|
||||
<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"></a>23.2.4 Inserting user code into generated files</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>
|
||||
|
||||
|
||||
<H2><a name="Lisp_nn8"></a>23.3 CLISP</H2>
|
||||
|
||||
|
||||
<p>
|
||||
<a href="http://clisp.cons.org">CLISP</a> is a feature-loaded
|
||||
implementation of common lisp which is portable across most of the
|
||||
operating system environments and hardware. CLISP includes an
|
||||
interpreter, a compiler, a debugger, CLOS, MOP, a foreign
|
||||
language interface, i18n, regular expressions, a socket
|
||||
interface, and more. An X11 interface is available through CLX,
|
||||
Garnet and CLUE/CLIO. Command line editing is provided by
|
||||
readline. CLISP runs Maxima, ACL2 and many other Common Lisp
|
||||
packages.
|
||||
</p>
|
||||
<p>
|
||||
To run the clisp module of SWIG requires very little effort, you
|
||||
just need to execute:
|
||||
</p>
|
||||
<div class="code"><pre>
|
||||
swig -clisp -module <i>module-name</i> <i>file-name</i>
|
||||
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Because of the high level nature of the CLISP FFI, the bindings
|
||||
generated by SWIG may not be absolutely correct, and you may need
|
||||
to modify them. The good thing is that you don't need to complex
|
||||
interface file for the CLISP module. The CLISP module tries to
|
||||
produce code which is both human readable and easily modifyable.
|
||||
</p>
|
||||
<H3><a name="Lisp_nn9"></a>23.3.1 Additional Commandline Options </H3>
|
||||
|
||||
|
||||
<p>
|
||||
The following table list the additional commandline options available for the CLISP module. They can also be seen by using:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
swig -clisp -help
|
||||
</pre></div>
|
||||
<br/>
|
||||
<table summary="CLISP specific options">
|
||||
<tr>
|
||||
<th>CLISP specific options</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-extern-all</td>
|
||||
<td>If this option is given then clisp definitions for all the functions<br/>
|
||||
and global variables will be created otherwise only definitions for<br/>
|
||||
externed functions and variables are created.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-generate-typedef</td>
|
||||
<td>If this option is given then def-c-type will be used to generate<br/>
|
||||
shortcuts according to the typedefs in the input.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<H3><a name="Lisp_nn10"></a>23.3.2 Details on CLISP bindings</H3>
|
||||
|
||||
|
||||
<p>
|
||||
As mentioned earlier the CLISP bindings generated by SWIG may need
|
||||
some modifications. The clisp module creates a lisp file with
|
||||
the same name as the module name. This
|
||||
lisp file contains a 'defpackage' declaration, with the
|
||||
package name same as the module name. This package uses the
|
||||
'common-lisp' and 'ffi' packages. Also, package exports all
|
||||
the functions, structures and variables for which an ffi
|
||||
binding was generated.<br/>
|
||||
After generating the defpackage statement, the clisp module also
|
||||
sets the default language.
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
(defpackage :test
|
||||
(:use :common-lisp :ffi)
|
||||
(:export
|
||||
:make-bar
|
||||
:bar-x
|
||||
:bar-y
|
||||
:bar-a
|
||||
:bar-b
|
||||
:bar-z
|
||||
:bar-n
|
||||
:pointer_func
|
||||
:func123
|
||||
:make-cfunr
|
||||
:lispsort_double
|
||||
:test123))
|
||||
|
||||
(in-package :test)
|
||||
|
||||
(default-foreign-language :stdc)
|
||||
</pre></div>
|
||||
<p>
|
||||
The ffi wrappers for functions and variables are generated as shown
|
||||
below. When functions have arguments of type "double * array",
|
||||
SWIG doesn't knows whether it is an 'out' argument or it is
|
||||
an array which will be passed, so SWIG plays it safe by
|
||||
declaring it as an '(array (ffi:c-ptr DOUBLE-FLOAT))'. For
|
||||
arguments of type "int **z[100]" where SWIG has more
|
||||
information, i.e., it knows that 'z' is an array of pointers to
|
||||
pointers of integers, SWIG defines it to be '(z (ffi:c-ptr
|
||||
(ffi:c-array (ffi:c-ptr (ffi:c-ptr ffi:int)) 100)))'
|
||||
</p>
|
||||
<div class="code"><pre>
|
||||
extern "C" {
|
||||
int pointer_func(void (*ClosureFun)( void* _fun, void* _data, void* _evt ), int y);
|
||||
|
||||
int func123(div_t * x,int **z[100],int y[][1000][10]);
|
||||
|
||||
void lispsort_double (int n, double * array);
|
||||
|
||||
void test123(float x , double y);
|
||||
|
||||
}
|
||||
</pre></div>
|
||||
<div class="targetlang"><pre>
|
||||
(ffi:def-call-out pointer_func
|
||||
(:name "pointer_func")
|
||||
(:arguments (ClosureFun (ffi:c-function (:arguments (arg0 (ffi:c-pointer NIL))
|
||||
(arg1 (ffi:c-pointer NIL))
|
||||
(arg2 (ffi:c-pointer NIL)))
|
||||
(:return-type NIL)))
|
||||
(y ffi:int))
|
||||
(:return-type ffi:int)
|
||||
(:library +library-name+))
|
||||
|
||||
(ffi:def-call-out func123
|
||||
(:name "func123")
|
||||
(:arguments (x (ffi:c-pointer div_t))
|
||||
(z (ffi:c-ptr (ffi:c-array (ffi:c-ptr (ffi:c-ptr ffi:int)) 100)))
|
||||
(y (ffi:c-ptr (ffi:c-ptr (ffi:c-array ffi:int (1000 10))))))
|
||||
(:return-type ffi:int)
|
||||
(:library +library-name+))
|
||||
|
||||
|
||||
(ffi:def-call-out lispsort_double
|
||||
(:name "lispsort_double")
|
||||
(:arguments (n ffi:int)
|
||||
(array (ffi:c-ptr DOUBLE-FLOAT)))
|
||||
(:return-type NIL)
|
||||
(:library +library-name+))
|
||||
|
||||
(ffi:def-call-out test123
|
||||
(:name "test")
|
||||
(:arguments (x SINGLE-FLOAT)
|
||||
(y DOUBLE-FLOAT))
|
||||
(:return-type NIL)
|
||||
(:library +library-name+))
|
||||
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
The module also handles strutcures and #define constants as shown
|
||||
below. SWIG automatically adds the constructors and accessors
|
||||
created for the struct to the list of symbols exported by the
|
||||
package.
|
||||
</p>
|
||||
<div class="code"><pre>
|
||||
struct bar {
|
||||
short x, y;
|
||||
char a, b;
|
||||
int *z[1000];
|
||||
struct bar * n;
|
||||
};
|
||||
|
||||
#define max 1000
|
||||
</pre></div>
|
||||
<div class="targetlang"><pre>
|
||||
(ffi:def-c-struct bar
|
||||
(x :type ffi:short)
|
||||
(y :type ffi:short)
|
||||
(a :type character)
|
||||
(b :type character)
|
||||
(z :type (ffi:c-array (ffi:c-ptr ffi:int) 1000))
|
||||
(n :type (ffi:c-pointer bar)))
|
||||
|
||||
(defconstant max 1000)
|
||||
|
||||
</pre></div>
|
||||
|
||||
<H2><a name="Lisp_nn11"></a>23.4 UFFI </H2>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
1598
Doc/Manual/Lua.html
Normal file
1598
Doc/Manual/Lua.html
Normal file
File diff suppressed because it is too large
Load diff
75
Doc/Manual/Makefile
Normal file
75
Doc/Manual/Makefile
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# Makefile for generating the SWIG documentation
|
||||
#
|
||||
# Note that the htmldoc package needs to be installed, but requires patching (using the
|
||||
# margin-left.patch file from this directory) in order to correctly generate the pdf docs.
|
||||
# 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 PDF document and single page HTML version of the documentation.
|
||||
# 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 linkchecker 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: CCache.html
|
||||
python maketoc.py
|
||||
|
||||
CCache.html: ../../CCache/ccache.yo
|
||||
yodl2html -o CCache.html ../../CCache/ccache.yo
|
||||
|
||||
# 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:
|
||||
tidy -errors --gnu-emacs yes -quiet index.html
|
||||
tidy -errors --gnu-emacs yes -quiet Sections.html
|
||||
all=`sed '/^#/d' chapters | grep -v CCache.html`; for a in $$all; do tidy -errors --gnu-emacs yes -quiet $$a; done;
|
||||
|
||||
generate: swightml.book swigpdf.book
|
||||
htmldoc --batch swightml.book || true
|
||||
htmldoc --batch swigpdf.book || true
|
||||
python fixstyle.py SWIGDocumentation.html
|
||||
|
||||
swigpdf.book: chapters Sections.html
|
||||
echo "#HTMLDOC 1.8.24" > swigpdf.book
|
||||
echo -t pdf13 -f SWIGDocumentation.pdf $(HTMLDOC_OPTIONS) --stylesheet style.css >> swigpdf.book
|
||||
echo "Sections.html" >> swigpdf.book
|
||||
cat chapters >> swigpdf.book
|
||||
|
||||
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 swigpdf.book
|
||||
rm -f CCache.html
|
||||
rm -f SWIGDocumentation.html
|
||||
rm -f SWIGDocumentation.pdf
|
||||
|
||||
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 (can take a while - 30 mins)
|
||||
linkchecker:
|
||||
linkchecker --anchors Contents.html
|
||||
|
||||
946
Doc/Manual/Modula3.html
Normal file
946
Doc/Manual/Modula3.html
Normal file
|
|
@ -0,0 +1,946 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and Modula-3</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF">
|
||||
<H1><a name="Modula3"></a>25 SWIG and Modula-3</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 of
|
||||
<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"></a>25.1 Overview</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"></a>25.1.1 Motivation</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 be still 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 Module-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 Module-3 module into
|
||||
a C/C++ project.
|
||||
</p>
|
||||
|
||||
<H2><a name="Modula3_conception"></a>25.2 Conception</H2>
|
||||
|
||||
|
||||
<H3><a name="Modula3_cinterface"></a>25.2.1 Interfaces to C libraries</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
|
||||
<a href="../../Lib/modula3/modula3.swg"><tt>modula3.swg</tt></a>
|
||||
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"></a>25.2.2 Interfaces to C++ libraries</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"></a>25.3 Preliminaries</H2>
|
||||
|
||||
|
||||
<H3><a name="Modula3_compilers"></a>25.3.1 Compilers</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 library file
|
||||
<a href="../../Lib/modula3/modula3.swg"><tt>modula3.swg</tt></a>
|
||||
may do so.
|
||||
For testing examples I use Critical Mass cm3.
|
||||
</p>
|
||||
|
||||
|
||||
<H3><a name="Modula3_commandline"></a>25.3.2 Additional Commandline Options</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"></a>25.4 Modula-3 typemaps</H2>
|
||||
|
||||
|
||||
<H3><a name="Modula3_inoutparam"></a>25.4.1 Inputs and outputs</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 typemap library
|
||||
<a href="../../Lib/modula3/modula3.swg"><tt>modula3.swg</tt></a>
|
||||
.
|
||||
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"></a>25.4.2 Subranges, Enumerations, Sets</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"></a>25.4.3 Objects</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"></a>25.4.4 Imports</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 typemap library
|
||||
<a href="../../Lib/modula3/modula3.swg"><tt>modula3.swg</tt></a>
|
||||
.
|
||||
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"></a>25.4.5 Exceptions</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"></a>25.4.6 Example</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"></a>25.5 More hints to the generator</H2>
|
||||
|
||||
|
||||
<H3><a name="Modula3_features"></a>25.5.1 Features</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"></a>25.5.2 Pragmas</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"></a>25.6 Remarks</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>
|
||||
348
Doc/Manual/Modules.html
Normal file
348
Doc/Manual/Modules.html
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Working with Modules</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<H1><a name="Modules"></a>15 Working with Modules</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"></a>15.1 Modules Introduction</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"></a>15.2 Basics</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. Oftentimes
|
||||
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"></a>15.3 The SWIG runtime code</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"></a>15.4 External access to the runtime</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, run the following command:
|
||||
|
||||
<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"></a>15.5 A word of caution about static libraries</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"></a>15.6 References</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"></a>15.7 Reducing the wrapper file size</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>
|
||||
71
Doc/Manual/Mzscheme.html
Normal file
71
Doc/Manual/Mzscheme.html
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<!-- Hand-written HTML -->
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and MzScheme</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
|
||||
<H1><a name="Mzscheme"></a>26 SWIG and MzScheme</H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#MzScheme_nn2">Creating native MzScheme structures</a>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
This section contains information on SWIG's support of MzScheme.
|
||||
|
||||
<H2><a name="MzScheme_nn2"></a>26.1 Creating native MzScheme structures</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>
|
||||
|
||||
<p>
|
||||
That's pretty much it. It works with nested structs as well.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
991
Doc/Manual/Ocaml.html
Normal file
991
Doc/Manual/Ocaml.html
Normal file
|
|
@ -0,0 +1,991 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and Ocaml</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
</head>
|
||||
<body bgcolor="#ffffff">
|
||||
<a name="n1"></a>
|
||||
<H1><a name="Ocaml"></a>27 SWIG and Ocaml</H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#Ocaml_nn2">Preliminaries</a>
|
||||
<ul>
|
||||
<li><a href="#Ocaml_nn3">Running SWIG</a>
|
||||
<li><a href="#Ocaml_nn4">Compiling the code</a>
|
||||
<li><a href="#Ocaml_nn5">The camlp4 module</a>
|
||||
<li><a href="#Ocaml_nn6">Using your module</a>
|
||||
<li><a href="#Ocaml_nn7">Compilation problems and compiling with C++</a>
|
||||
</ul>
|
||||
<li><a href="#Ocaml_nn8">The low-level Ocaml/C interface</a>
|
||||
<ul>
|
||||
<li><a href="#Ocaml_nn9">The generated module</a>
|
||||
<li><a href="#Ocaml_nn10">Enums</a>
|
||||
<ul>
|
||||
<li><a href="#Ocaml_nn11">Enum typing in Ocaml</a>
|
||||
</ul>
|
||||
<li><a href="#Ocaml_nn12">Arrays</a>
|
||||
<ul>
|
||||
<li><a href="#Ocaml_nn13">Simple types of bounded arrays</a>
|
||||
<li><a href="#Ocaml_nn14">Complex and unbounded arrays</a>
|
||||
<li><a href="#Ocaml_nn15">Using an object</a>
|
||||
<li><a href="#Ocaml_nn16">Example typemap for a function taking float * and int</a>
|
||||
</ul>
|
||||
<li><a href="#Ocaml_nn17">C++ Classes</a>
|
||||
<ul>
|
||||
<li><a href="#Ocaml_nn18">STL vector and string Example</a>
|
||||
<li><a href="#Ocaml_nn19">C++ Class Example</a>
|
||||
<li><a href="#Ocaml_nn20">Compiling the example</a>
|
||||
<li><a href="#Ocaml_nn21">Sample Session</a>
|
||||
</ul>
|
||||
<li><a href="#Ocaml_nn22">Director Classes</a>
|
||||
<ul>
|
||||
<li><a href="#Ocaml_nn23">Director Introduction</a>
|
||||
<li><a href="#Ocaml_nn24">Overriding Methods in Ocaml</a>
|
||||
<li><a href="#Ocaml_nn25">Director Usage Example</a>
|
||||
<li><a href="#Ocaml_nn26">Creating director objects</a>
|
||||
<li><a href="#Ocaml_nn27">Typemaps for directors, <tt>directorin, directorout, directorargout</tt></a>
|
||||
<li><a href="#Ocaml_nn28"><tt>directorin</tt> typemap</a>
|
||||
<li><a href="#Ocaml_nn29"><tt>directorout</tt> typemap</a>
|
||||
<li><a href="#Ocaml_nn30"><tt>directorargout</tt> typemap</a>
|
||||
</ul>
|
||||
<li><a href="#Ocaml_nn31">Exceptions</a>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
This chapter describes SWIG's
|
||||
support of Ocaml. Ocaml is a relatively recent addition to the ML family,
|
||||
and is a recent addition to SWIG. It's the second compiled, typed
|
||||
language to be added. Ocaml has widely acknowledged benefits for engineers,
|
||||
mostly derived from a sophisticated type system, compile-time checking
|
||||
which eliminates several classes of common programming errors, and good
|
||||
native performance. While all of this is wonderful, there are well-written
|
||||
C and C++ libraries that Ocaml users will want to take advantage of as
|
||||
part of their arsenal (such as SSL and gdbm), as well as their own mature
|
||||
C and C++ code. SWIG allows this code to be used in a natural, type-safe
|
||||
way with Ocaml, by providing the necessary, but repetitive glue code
|
||||
which creates and uses Ocaml values to communicate with C and C++ code.
|
||||
In addition, SWIG also produces the needed Ocaml source that binds
|
||||
variants, functions, classes, etc.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you're not familiar with the Objective Caml language, you can visit
|
||||
<a href="http://www.ocaml.org/">The Ocaml Website</a>.
|
||||
</p>
|
||||
|
||||
<H2><a name="Ocaml_nn2"></a>27.1 Preliminaries</H2>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG 1.3 works with Ocaml 3.04 and above. Given the choice,
|
||||
you should use the latest stable release. The SWIG Ocaml module has
|
||||
been tested on Linux (x86,PPC,Sparc) and Cygwin on Windows. The
|
||||
best way to determine whether your system will work is to compile the
|
||||
examples and test-suite which come with SWIG. You can do this by running
|
||||
<tt>make check</tt> from the SWIG root directory after installing SWIG.
|
||||
The Ocaml module has been tested using the system's dynamic linking (the
|
||||
usual -lxxx against libxxx.so, as well as with Gerd Stolpmann's
|
||||
<a
|
||||
href="http://www.ocaml-programming.de/packages/documentation/dl/">Dl package
|
||||
</a>. The ocaml_dynamic and ocaml_dynamic_cpp targets in the
|
||||
file Examples/Makefile illustrate how to compile and link SWIG modules that
|
||||
will be loaded dynamically. This has only been tested on Linux so far.
|
||||
</p>
|
||||
|
||||
<H3><a name="Ocaml_nn3"></a>27.1.1 Running SWIG</H3>
|
||||
|
||||
|
||||
<p>
|
||||
The basics of getting a SWIG Ocaml module up and running
|
||||
can be seen from one of SWIG's example Makefiles, but is also described
|
||||
here. To build an Ocaml module, run SWIG using the <tt>-ocaml</tt>
|
||||
option.
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%swig -ocaml example.i
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p> This will produce 3 files. The file <tt>example_wrap.c</tt> contains
|
||||
all of the C code needed to build an Ocaml module. To build the module,
|
||||
you will compile the file <tt>example_wrap.c</tt> with <tt>ocamlc</tt> or
|
||||
<tt>ocamlopt</tt> to create the needed .o file. You will need to compile
|
||||
the resulting .ml and .mli files as well, and do the final link with -custom
|
||||
(not needed for native link). </p>
|
||||
|
||||
<H3><a name="Ocaml_nn4"></a>27.1.2 Compiling the code</H3>
|
||||
|
||||
|
||||
<p>
|
||||
The O'Caml SWIG module now requires you to compile a module (<tt>Swig</tt>)
|
||||
separately. In addition to aggregating common SWIG functionality, the Swig
|
||||
module contains the data structure that represents C/C++ values. This allows
|
||||
easier data sharing between modules if two or more are combined, because
|
||||
the type of each SWIG'ed module's c_obj is derived from Swig.c_obj_t. This
|
||||
also allows SWIG to acquire new conversions painlessly, as well as giving
|
||||
the user more freedom with respect to custom typing.
|
||||
|
||||
Use <tt>ocamlc</tt> or <tt>ocamlopt</tt> to compile your
|
||||
SWIG interface like:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
% swig -ocaml -co swig.mli ; swig -ocaml co swig.ml
|
||||
% ocamlc -c swig.mli ; ocamlc -c swig.ml
|
||||
% ocamlc -c -ccopt "-I/usr/include/foo" example_wrap.c
|
||||
% ocamlc -c example.mli
|
||||
% ocamlc -c example.ml
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p> <tt>ocamlc</tt> is aware of .c files and knows how to handle them. Unfortunately,
|
||||
it does not know about .cxx, .cc, or .cpp files, so when SWIG is invoked
|
||||
in C++ mode, you must: </p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
% cp example_wrap.cxx example_wrap.cxx.c<br>% ocamlc -c ... -ccopt -xc++ example_wrap.cxx.c<br>% ...<br>
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<H3><a name="Ocaml_nn5"></a>27.1.3 The camlp4 module</H3>
|
||||
|
||||
|
||||
<p>
|
||||
The camlp4 module (swigp4.ml -> swigp4.cmo) contains a simple rewriter which
|
||||
makes C++ code blend more seamlessly with objective caml code. It's use is
|
||||
optional, but encouraged. The source file is included in the Lib/ocaml
|
||||
directory of the SWIG source distribution. You can checkout this file with
|
||||
<tt>"swig -ocaml -co swigp4.ml"</tt>. You should compile the file with
|
||||
<tt>"ocamlc -I `camlp4 -where` -pp 'camlp4o pa_extend.cmo q_MLast.cmo' -c swigp4.ml"</tt>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The basic principle of the module is to recognize certain non-caml expressions
|
||||
and convert them for use with C++ code as interfaced by SWIG. The camlp4
|
||||
module is written to work with generated SWIG interfaces, and probably isn't
|
||||
great to use with anything else.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Here are the main rewriting rules:
|
||||
</p>
|
||||
|
||||
<table border="1" summary="Rewriting rules">
|
||||
<tr><th>Input</th><th>Rewritten to</th></tr>
|
||||
<tr><td>f'( ... ) as in<br> atoi'("0") or<br> _exit'(0)</td>
|
||||
<td>f(C_list [ ... ]) as in<br> atoi (C_list [ C_string "0" ]) or<br> _exit (C_list [ C_int 0 ])</td></tr>
|
||||
<tr><td>object -> method ( ... )</td><td>(invoke object) "method" (C_list [ ... ])</td></tr>
|
||||
<tr><td>
|
||||
object <i>'binop</i> argument as in<br>
|
||||
a '+= b</td>
|
||||
<td>
|
||||
(invoke object) "+=" argument as in<br>
|
||||
(invoke a) "+=" b<td></tr>
|
||||
<tr><th colspan=2>Note that because camlp4 always recognizes <<
|
||||
and >>, they are replaced by lsl and lsr in operator names.
|
||||
<tr><td>
|
||||
<i>'unop</i> object as in<br>
|
||||
'! a
|
||||
</td><td>
|
||||
(invoke a) "!" C_void</td></tr>
|
||||
<tr><td>
|
||||
<b>Smart pointer access like this</b><br>
|
||||
object '-> method ( args )<br>
|
||||
</td><td>
|
||||
(invoke (invoke object "->" C_void))
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
<b>Invoke syntax</b><br>
|
||||
object . '( ... )
|
||||
</td><td>
|
||||
(invoke object) "()" (C_list [ ... ])
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
<b>Array syntax</b><br>
|
||||
object '[ 10 ]
|
||||
</td><td>
|
||||
(invoke object) "[]" (C_int 10)
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
<b>Assignment syntax</b><br>
|
||||
let a = '10 and b = '"foo" and c = '1.0 and d = 'true
|
||||
</td><td>
|
||||
let a = C_int 10 and b = C_string "foo" and c = C_double 1.0 and d = C_bool true
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
<b>Cast syntax</b><br>
|
||||
let a = _atoi '("2") as int<br>
|
||||
let b = (getenv "PATH") to string<br>
|
||||
This works for int, string, float, bool
|
||||
</td><td>
|
||||
let a = get_int (_atoi (C_string "2"))<br>
|
||||
let b = C_string (getenv "PATH")
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<H3><a name="Ocaml_nn6"></a>27.1.4 Using your module</H3>
|
||||
|
||||
|
||||
<p>
|
||||
You can test-drive your module by building a
|
||||
toplevel ocaml interpreter. Consult the ocaml manual for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When linking any ocaml bytecode with your module, use the -custom
|
||||
option to build your functions into the primitive list. This
|
||||
option is not needed when you build native code.
|
||||
</p>
|
||||
|
||||
<H3><a name="Ocaml_nn7"></a>27.1.5 Compilation problems and compiling with C++</H3>
|
||||
|
||||
|
||||
<p>
|
||||
As mentioned above, .cxx files need special
|
||||
handling to be compiled with <tt>ocamlc</tt>. Other than that, C code
|
||||
that uses <tt>class</tt> as a non-keyword, and C code that is too
|
||||
liberal with pointer types may not compile under the C++ compiler.
|
||||
Most code meant to be compiled as C++ will not have problems.
|
||||
</p>
|
||||
|
||||
<H2><a name="Ocaml_nn8"></a>27.2 The low-level Ocaml/C interface</H2>
|
||||
|
||||
|
||||
<p>
|
||||
In order to provide access to overloaded functions, and
|
||||
provide sensible outputs from them, all C entities are represented as
|
||||
members of the c_obj type:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In the code as seen by the typemap
|
||||
writer, there is a value, swig_result, that always contains the
|
||||
current return data. It is a list, and must be appended with the
|
||||
caml_list_append function, or with functions and macros provided by
|
||||
objective caml.<br>
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
type c_obj =
|
||||
C_void
|
||||
| C_bool of bool
|
||||
| C_char of char
|
||||
| C_uchar of char
|
||||
| C_short of int
|
||||
| C_ushort of int
|
||||
| C_int of int
|
||||
| C_uint of int32
|
||||
| C_int32 of int32
|
||||
| C_int64 of int64
|
||||
| C_float of float
|
||||
| C_double of float
|
||||
| C_ptr of int64 * int64
|
||||
| C_array of c_obj array
|
||||
| C_list of c_obj list
|
||||
| C_obj of (string -> c_obj -> c_obj)
|
||||
| C_string of string
|
||||
| C_enum of c_enum_t
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
A few functions exist which generate and return these:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>caml_ptr_val receives a c_obj and returns a void *. This
|
||||
should be used for all pointer purposes.</li>
|
||||
<li>caml_long_val receives a c_obj and returns a long. This
|
||||
should be used for most integral purposes.<br>
|
||||
</li>
|
||||
<li>caml_val_ptr receives a void * and returns a c_obj.</li>
|
||||
<li>caml_val_bool receives a C int and returns a c_obj representing
|
||||
it's bool value.</li>
|
||||
<li>caml_val_(u)?(char|short|int|long|float|double) receives an
|
||||
appropriate C value and returns a c_obj representing it.</li>
|
||||
<li>caml_val_string receives a char * and returns a string value.</li>
|
||||
<li>caml_val_string_len receives a char * and a length and returns
|
||||
a string value.</li>
|
||||
<li>caml_val_obj receives a void * and an object type and returns
|
||||
a C_obj, which contains a closure giving method access.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Because of this style, a typemap can return any kind of value it
|
||||
wants from a function. This enables out typemaps and inout typemaps
|
||||
to work well. The one thing to remember about outputting values
|
||||
is that you must append them to the return list with swig_result = caml_list_append(swig_result,v).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This function will return a new list that has your element
|
||||
appended. Upon return to caml space, the fnhelper function
|
||||
beautifies the result. A list containing a single item degrades to
|
||||
only that item (i.e. [ C_int 3 ] -> C_int 3), and a list
|
||||
containing more than one item is wrapped in C_list (i.e. [ C_char
|
||||
'a' ; C_char 'b' -> C_list [ C_char 'a' ; C_char b
|
||||
]). This is in order to make return values easier to handle
|
||||
when functions have only one return value, such as constructors,
|
||||
and operators. In addition, string, pointer, and object
|
||||
values are interchangeable with respect to caml_ptr_val, so you can
|
||||
allocate memory as caml strings and still use the resulting
|
||||
pointers for C purposes, even using them to construct simple objects
|
||||
on. Note, though, that foreign C++ code does not respect the garbage
|
||||
collector, although the SWIG interface does.</p>
|
||||
|
||||
<p>
|
||||
The wild card type that you can use in lots of different ways is
|
||||
C_obj. It allows you to wrap any type of thing you like as an
|
||||
object using the same mechanism that the ocaml module
|
||||
does. When evaluated in caml_ptr_val, the returned value is
|
||||
the result of a call to the object's "&" operator, taken as a pointer.
|
||||
</p>
|
||||
<p>
|
||||
You should only construct values using objective caml, or using the
|
||||
functions caml_val_* functions provided as static functions to a SWIG
|
||||
ocaml module, as well as the caml_list_* functions. These functions
|
||||
provide everything a typemap needs to produce values. In addition,
|
||||
value items pass through directly, but you must make your own type
|
||||
signature for a function that uses value in this way.
|
||||
</p>
|
||||
|
||||
<H3><a name="Ocaml_nn9"></a>27.2.1 The generated module</H3>
|
||||
|
||||
|
||||
<p>
|
||||
The SWIG <tt>%module</tt> directive specifies the name of the Ocaml
|
||||
module to be generated. If you specified `<tt>%module example</tt>',
|
||||
then your Ocaml code will be accessible in the module Example. The
|
||||
module name is always capitalized as is the ocaml convention. Note
|
||||
that you must not use any Ocaml keyword to name your module. Remember
|
||||
that the keywords are not the same as the C++ ones.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can introduce extra code into the output wherever you like with SWIG.
|
||||
These are the places you can introduce code:
|
||||
<table border="1" summary="Extra code sections">
|
||||
<tr><td>"header"</td><td>This code is inserted near the beginning of the
|
||||
C wrapper file, before any function definitions.</td></tr>
|
||||
<tr><td>"wrapper"</td><td>This code is inserted in the function definition
|
||||
section.</td></tr>
|
||||
<tr><td>"runtime"</td><td>This code is inserted near the end of the C wrapper
|
||||
file.</td></tr>
|
||||
<tr><td>"mli"</td><td>This code is inserted into the caml interface file.
|
||||
Special signatures should be inserted here.
|
||||
</td></tr>
|
||||
<tr><td>"ml"</td><td>This code is inserted in the caml code defining the
|
||||
interface to your C code. Special caml code, as well as any initialization
|
||||
which should run when the module is loaded may be inserted here.
|
||||
</td></tr>
|
||||
<tr><td>"classtemplate"</td><td>The "classtemplate" place is special because
|
||||
it describes the output SWIG will generate for class definitions.
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<H3><a name="Ocaml_nn10"></a>27.2.2 Enums</H3>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG will wrap enumerations as polymorphic variants in the output
|
||||
Ocaml code, as above in C_enum. In order to support all
|
||||
C++-style uses of enums, the function int_to_enum and enum_to_int are
|
||||
provided for ocaml code to produce and consume these values as
|
||||
integers. Other than that, correct uses of enums will not have
|
||||
a problem. Since enum labels may overlap between enums, the
|
||||
enum_to_int and int_to_enum functions take an enum type label as an
|
||||
argument. Example:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%module enum_test
|
||||
%{
|
||||
enum c_enum_type { a = 1, b, c = 4, d = 8 };
|
||||
%}
|
||||
enum c_enum_type { a = 1, b, c = 4, d = 8 };
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
The output mli contains:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
type c_enum_type = [
|
||||
`unknown
|
||||
| `c_enum_type
|
||||
]
|
||||
type c_enum_tag = [
|
||||
`int of int
|
||||
| `a
|
||||
| `b
|
||||
| `c
|
||||
| `d
|
||||
]
|
||||
val int_to_enum c_enum_type -> int -> c_obj
|
||||
val enum_to_int c_enum_type -> c_obj -> c_obj
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
So it's possible to do this:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
bash-2.05a$ ocamlmktop -custom enum_test_wrap.o enum_test.cmo -o enum_test_top
|
||||
bash-2.05a$ ./enum_test_top
|
||||
Objective Caml version 3.04
|
||||
|
||||
# open Enum_test ;;
|
||||
# let x = C_enum `a ;;
|
||||
val x : Enum_test.c_obj = C_enum `a
|
||||
# enum_to_int `c_enum_type x ;;
|
||||
- : Enum_test.c_obj = C_int 1
|
||||
# int_to_enum `c_enum_type 4 ;;
|
||||
- : Enum_test.c_obj = C_enum `c
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<H4><a name="Ocaml_nn11"></a>27.2.2.1 Enum typing in Ocaml</H4>
|
||||
|
||||
|
||||
<p>
|
||||
The ocaml SWIG module now has support for loading and using multiple SWIG
|
||||
modules at the same time. This enhances modularity, but presents problems
|
||||
when used with a language which assumes that each module's types are complete
|
||||
at compile time. In order to achieve total soundness enum types are now
|
||||
isolated per-module. The type issue matters when values are shared between
|
||||
functions imported from different modules. You must convert values to master
|
||||
values using the swig_val function before sharing them with another module.
|
||||
</p>
|
||||
|
||||
<H3><a name="Ocaml_nn12"></a>27.2.3 Arrays</H3>
|
||||
|
||||
|
||||
<H4><a name="Ocaml_nn13"></a>27.2.3.1 Simple types of bounded arrays</H4>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG has support for array types, but you generally will need to provide
|
||||
a typemap to handle them. You can currently roll your own, or expand
|
||||
some of the macros provided (but not included by default) with the SWIG
|
||||
distribution.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
By including "carray.i", you will get access to some macros that help you
|
||||
create typemaps for array types fairly easily.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<tt>%make_simple_array_typemap</tt> is the easiest way to get access to
|
||||
arrays of simple types with known bounds in your code, but this only works
|
||||
for arrays whose bounds are completely specified.
|
||||
</p>
|
||||
|
||||
<H4><a name="Ocaml_nn14"></a>27.2.3.2 Complex and unbounded arrays</H4>
|
||||
|
||||
|
||||
<p>
|
||||
Unfortunately, unbounded arrays and pointers can't be handled in a
|
||||
completely general way by SWIG, because the end-condition of such an
|
||||
array can't be predicted. In some cases, it will be by consent
|
||||
(e.g. an array of four or more chars), sometimes by explicit length
|
||||
(char *buffer, int len), and sometimes by sentinel value (0,-1,etc.).
|
||||
SWIG can't predict which of these methods will be used in the array,
|
||||
so you have to specify it for yourself in the form of a typemap.
|
||||
</p>
|
||||
|
||||
<H4><a name="Ocaml_nn15"></a>27.2.3.3 Using an object</H4>
|
||||
|
||||
|
||||
<p>
|
||||
It's possible to use C++ to your advantage by creating a simple object that
|
||||
provides access to your array. This may be more desirable in some cases,
|
||||
since the object can provide bounds checking, etc., that prevents crashes.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Consider writing an object when the ending condition of your array is complex,
|
||||
such as using a required sentinel, etc.
|
||||
</p>
|
||||
|
||||
<H4><a name="Ocaml_nn16"></a>27.2.3.4 Example typemap for a function taking float * and int</H4>
|
||||
|
||||
|
||||
<p>
|
||||
This is a simple example <tt>in</tt> typemap for an array of float, where the
|
||||
length of the array is specified as an extra parameter. Other such typemaps
|
||||
will work similarly. In the example, the function printfloats is called with
|
||||
a float array, and specified length. The actual length reported in the len
|
||||
argument is the length of the array passed from ocaml, making passing an array
|
||||
into this type of function convenient.
|
||||
</p>
|
||||
|
||||
<table border="1" bgcolor="#dddddd" summary="float * and int typemap example">
|
||||
<tr><th><center>tarray.i</center></th></tr>
|
||||
<tr><td><pre>
|
||||
%module tarray
|
||||
%{
|
||||
#include <stdio.h>
|
||||
|
||||
void printfloats( float *tab, int len ) {
|
||||
int i;
|
||||
|
||||
for( i = 0; i < len; i++ ) {
|
||||
printf( "%f ", tab[i] );
|
||||
}
|
||||
|
||||
printf( "\n" );
|
||||
}
|
||||
%}
|
||||
|
||||
%typemap(in) (float *tab, int len) {
|
||||
int i;
|
||||
/* $*1_type */
|
||||
$2 = caml_array_len($input);
|
||||
$1 = ($*1_type *)malloc( $2 * sizeof( float ) );
|
||||
for( i = 0; i < $2; i++ ) {
|
||||
$1[i] = caml_double_val(caml_array_nth($input,i));
|
||||
}
|
||||
}
|
||||
|
||||
void printfloats( float *tab, int len );
|
||||
</pre></td></tr>
|
||||
<tr><th>Sample Run</th></tr>
|
||||
<tr><td><pre>
|
||||
# open Tarray ;;
|
||||
# _printfloats (C_array [| C_double 1.0 ; C_double 3.0 ; C_double 5.6666 |]) ;;
|
||||
1.000000 3.000000 5.666600
|
||||
- : Tarray.c_obj = C_void
|
||||
</pre></td></tr></table>
|
||||
|
||||
|
||||
<H3><a name="Ocaml_nn17"></a>27.2.4 C++ Classes</H3>
|
||||
|
||||
|
||||
<p>
|
||||
C++ classes, along with structs and unions are represented by C_obj
|
||||
(string -> c_obj -> c_obj) wrapped closures. These objects
|
||||
contain a method list, and a type, which allow them to be used like
|
||||
C++ objects. When passed into typemaps that use pointers, they
|
||||
degrade to pointers through their "&" method. Every method
|
||||
an object has is represented as a string in the object's method table,
|
||||
and each method table exists in memory only once. In addition
|
||||
to any other operators an object might have, certain builtin ones are
|
||||
provided by SWIG: (all of these take no arguments (C_void))
|
||||
</p>
|
||||
|
||||
<table summary="SWIG provided operators">
|
||||
<tr><td>"~"</td><td>Delete this object</td></tr>
|
||||
<tr><td>"&"</td><td>Return an ordinary C_ptr value representing this
|
||||
object's address</td></tr>
|
||||
<tr><td>"sizeof"</td><td>If enabled with ("sizeof"="1") on the module node,
|
||||
return the object's size in char.</td></tr>
|
||||
<tr><td>":methods"</td><td>Returns a list of strings containing the names of
|
||||
the methods this object contains</td></tr>
|
||||
<tr><td>":classof"</td><td>Returns the name of the class this object belongs
|
||||
to.</td></tr>
|
||||
<tr><td>":parents"</td><td>Returns a list of all direct parent classes which
|
||||
have been wrapped by SWIG.</td></tr>
|
||||
<tr><td>"::[parent-class]"</td><td>Returns a view of the object as the
|
||||
indicated parent class. This is mainly used internally by the SWIG module,
|
||||
but may be useful to client programs.</td></tr>
|
||||
<tr><td>"[member-variable]"</td><td>Each member variable is wrapped as a
|
||||
method with an optional parameter.
|
||||
Called with one argument, the member variable is set to the value of the
|
||||
argument. With zero arguments, the value is returned.
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
Note that this string belongs to the wrapper object, and not
|
||||
the underlying pointer, so using create_[x]_from_ptr alters the
|
||||
returned value for the same object.
|
||||
</p>
|
||||
|
||||
<H4><a name="Ocaml_nn18"></a>27.2.4.1 STL vector and string Example</H4>
|
||||
|
||||
|
||||
<p>
|
||||
Standard typemaps are now provided for STL vector and string. More are in
|
||||
the works. STL strings are passed just like normal strings, and returned
|
||||
as strings. STL string references don't mutate the original string, (which
|
||||
might be surprising), because Ocaml strings are mutable but have fixed
|
||||
length. Instead, use multiple returns, as in the argout_ref example.
|
||||
</p>
|
||||
|
||||
<table border="1" bgcolor="#dddddd" summary="STL vector and string example">
|
||||
<tr><th><center>example.i</center></th></tr>
|
||||
<tr><td><pre>
|
||||
%module example
|
||||
%{
|
||||
#include "example.h"
|
||||
%}
|
||||
|
||||
%include <stl.i>
|
||||
|
||||
namespace std {
|
||||
%template(StringVector) std::vector < string >;
|
||||
};
|
||||
|
||||
%include "example.h"
|
||||
</pre></td></tr>
|
||||
<tr><td><font size="-1"><i>This example is in Examples/ocaml/stl
|
||||
</i></font></td></tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
Since there's a makefile in that directory, the example is easy to build.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Here's a sample transcript of an interactive session using a string vector
|
||||
after making a toplevel (make toplevel). This example uses the camlp4
|
||||
module.
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
bash-2.05a$ ./example_top
|
||||
Objective Caml version 3.06
|
||||
|
||||
Camlp4 Parsing version 3.06
|
||||
|
||||
# open Swig ;;
|
||||
# open Example ;;
|
||||
# let x = new_StringVector '() ;;
|
||||
val x : Example.c_obj = C_obj <fun>
|
||||
# x -> ":methods" () ;;
|
||||
- : Example.c_obj =
|
||||
C_list
|
||||
[C_string "nop"; C_string "size"; C_string "empty"; C_string "clear";
|
||||
C_string "push_back"; C_string "[]"; C_string "="; C_string "set";
|
||||
C_string "~"; C_string "&"; C_string ":parents"; C_string ":classof";
|
||||
C_string ":methods"]
|
||||
# x -> push_back ("foo") ;;
|
||||
- : Example.c_obj = C_void
|
||||
# x -> push_back ("bar") ;;
|
||||
- : Example.c_obj = C_void
|
||||
# x -> push_back ("baz") ;;
|
||||
- : Example.c_obj = C_void
|
||||
# x '[1] ;;
|
||||
- : Example.c_obj = C_string "bar"
|
||||
# x -> set (1,"spam") ;;
|
||||
- : Example.c_obj = C_void
|
||||
# x '[1] ;;
|
||||
- : Example.c_obj = C_string "spam"
|
||||
# for i = 0 to (x -> size() as int) - 1 do
|
||||
print_endline ((x '[i to int]) as string)
|
||||
done ;;
|
||||
foo
|
||||
bar
|
||||
baz
|
||||
- : unit = ()
|
||||
#
|
||||
</pre></div>
|
||||
|
||||
<H4><a name="Ocaml_nn19"></a>27.2.4.2 C++ Class Example</H4>
|
||||
|
||||
|
||||
<p>
|
||||
Here's a simple example using Trolltech's Qt Library:
|
||||
</p>
|
||||
|
||||
<table border="1" bgcolor="#dddddd" summary="Qt Library example">
|
||||
<tr><th><center>qt.i</center></th></tr>
|
||||
<tr><td><pre>
|
||||
%module qt
|
||||
%{
|
||||
#include <qapplication.h>
|
||||
#include <qpushbutton.h>
|
||||
%}
|
||||
class QApplication {
|
||||
public:
|
||||
QApplication( int argc, char **argv );
|
||||
void setMainWidget( QWidget *widget );
|
||||
void exec();
|
||||
};
|
||||
|
||||
class QPushButton {
|
||||
public:
|
||||
QPushButton( char *str, QWidget *w );
|
||||
void resize( int x, int y );
|
||||
void show();
|
||||
};
|
||||
</pre></td></tr></table>
|
||||
|
||||
<H4><a name="Ocaml_nn20"></a>27.2.4.3 Compiling the example</H4>
|
||||
|
||||
|
||||
<div class="code"><pre>
|
||||
bash-2.05a$ QTPATH=/your/qt/path
|
||||
bash-2.05a$ for file in swig.mli swig.ml swigp4.ml ; do swig -ocaml -co $file ; done
|
||||
bash-2.05a$ ocamlc -c swig.mli ; ocamlc -c swig.ml
|
||||
bash-2.05a$ ocamlc -I `camlp4 -where` -pp "camlp4o pa_extend.cmo q_MLast.cmo" -c swigp4.ml
|
||||
bash-2.05a$ swig -ocaml -c++ -I$QTPATH/include qt.i
|
||||
bash-2.05a$ mv qt_wrap.cxx qt_wrap.c
|
||||
bash-2.05a$ ocamlc -c -ccopt -xc++ -ccopt -g -g -ccopt -I$QTPATH/include qt_wrap.c
|
||||
bash-2.05a$ ocamlc -c qt.mli
|
||||
bash-2.05a$ ocamlc -c qt.ml
|
||||
bash-2.05a$ ocamlmktop -custom swig.cmo -I `camlp4 -where` \
|
||||
camlp4o.cma swigp4.cmo qt_wrap.o qt.cmo -o qt_top -cclib \
|
||||
-L$QTPATH/lib -cclib -lqt
|
||||
</pre></div>
|
||||
|
||||
<H4><a name="Ocaml_nn21"></a>27.2.4.4 Sample Session</H4>
|
||||
|
||||
|
||||
<div class="code"><pre>
|
||||
bash-2.05a$ ./qt_top
|
||||
Objective Caml version 3.06
|
||||
|
||||
Camlp4 Parsing version 3.06
|
||||
|
||||
# open Swig ;;
|
||||
# open Qt ;;
|
||||
# let a = new_QApplication '(0,0) ;;
|
||||
val a : Qt.c_obj = C_obj <fun>
|
||||
# let hello = new_QPushButton '("hi",0) ;;
|
||||
val hello : Qt.c_obj = C_obj <fun>
|
||||
# hello -> resize (100,30) ;;
|
||||
- : Qt.c_obj = C_void
|
||||
# hello -> show () ;;
|
||||
- : Qt.c_obj = C_void
|
||||
# a -> exec () ;;
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Assuming you have a working installation of QT, you will see a window
|
||||
containing the string "hi" in a button.
|
||||
</p>
|
||||
|
||||
<H3><a name="Ocaml_nn22"></a>27.2.5 Director Classes</H3>
|
||||
|
||||
|
||||
<H4><a name="Ocaml_nn23"></a>27.2.5.1 Director Introduction</H4>
|
||||
|
||||
|
||||
<p>
|
||||
Director classes are classes which allow Ocaml code to override the public
|
||||
methods of a C++ object. This facility allows the user to use C++ libraries
|
||||
that require a derived class to provide application specific functionality in
|
||||
the context of an application or utility framework.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can turn on director classes by using an optional module argument like
|
||||
this:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%module(directors="1")
|
||||
|
||||
...
|
||||
|
||||
// Turn on the director class for a specific class like this:
|
||||
%feature("director")
|
||||
class foo {
|
||||
...
|
||||
};
|
||||
</pre></div>
|
||||
|
||||
<H4><a name="Ocaml_nn24"></a>27.2.5.2 Overriding Methods in Ocaml</H4>
|
||||
|
||||
|
||||
<p>
|
||||
Because the Ocaml language module treats C++ method calls as calls to a
|
||||
certain function, all you need to do is to define the function that will
|
||||
handle the method calls in terms of the public methods of the object, and
|
||||
any other relevant information. The function <tt>new_derived_object</tt>
|
||||
uses a stub class to call your methods in place of the ones provided by the
|
||||
underlying implementation. The object you receive is the underlying object,
|
||||
so you are free to call any methods you want from within your derived method.
|
||||
Note that calls to the underlying object do not invoke Ocaml code. You need
|
||||
to handle that yourself.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<tt>new_derived_object</tt> receives your function, the function that creates
|
||||
the underlying object, and any constructor arguments, and provides an
|
||||
object that you can use in any usual way. When C++ code calls one of the
|
||||
object's methods, the object invokes the Ocaml function as if it had been
|
||||
invoked from Ocaml, allowing any method definitions to override the C++ ones.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In this example, I'll examine the objective caml code involved in providing
|
||||
an overloaded class. This example is contained in Examples/ocaml/shapes.
|
||||
</p>
|
||||
|
||||
<H4><a name="Ocaml_nn25"></a>27.2.5.3 Director Usage Example</H4>
|
||||
|
||||
|
||||
<table border="1" bgcolor="#dddddd" summary="Director usage example">
|
||||
<tr><th><center>example_prog.ml</center>
|
||||
</th></tr>
|
||||
<tr><td><pre>
|
||||
open Swig
|
||||
open Example
|
||||
|
||||
...
|
||||
|
||||
let triangle_class pts ob meth args =
|
||||
match meth with
|
||||
"cover" ->
|
||||
(match args with
|
||||
C_list [ x_arg ; y_arg ] ->
|
||||
let xa = x_arg as float
|
||||
and ya = y_arg as float in
|
||||
(point_in_triangle pts xa ya) to bool
|
||||
| _ -> raise (Failure "cover needs two double arguments."))
|
||||
| _ -> (invoke ob) meth args ;;
|
||||
|
||||
let triangle =
|
||||
new_derived_object
|
||||
new_shape
|
||||
(triangle_class ((0.0,0.0),(0.5,1.0),(1.0,0.0)))
|
||||
'() ;;
|
||||
|
||||
let _ = _draw_shape_coverage '(triangle, C_int 60, C_int 20) ;;
|
||||
</pre></td></tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
This is the meat of what you need to do. The actual "class" definition
|
||||
containing the overloaded method is defined in the function triangle_class.
|
||||
This is a lot like the class definitions emitted by SWIG, if you look at
|
||||
example.ml, which is generated when SWIG consumes example.i. Basically,
|
||||
you are given the arguments as a c_obj and the method name as a string, and
|
||||
you must intercept the method you are interested in and provide whatever
|
||||
return value you need. Bear in mind that the underlying C++ code needs the
|
||||
right return type, or an exception will be thrown. This exception will
|
||||
generally be Failure, or NotObject. You must call other ocaml methods that
|
||||
you rely on yourself. Due to the way directors are implemented, method
|
||||
calls on your object from with ocaml code will always invoke C++ methods
|
||||
even if they are overridden in ocaml.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In the example, the draw_shape_coverage function plots the indicated number
|
||||
of points as either covered (<tt>x</tt>) or uncovered ( ) between
|
||||
0 and 1 on the X and Y axes. Your shape implementation can provide any
|
||||
coverage map it likes, as long as it responds to the "cover" method call
|
||||
with a boolean return (the underlying method returns bool). This might allow
|
||||
a tricky shape implementation, such as a boolean combination, to be expressed
|
||||
in a more effortless style in ocaml, while leaving the "engine" part of the
|
||||
program in C++.
|
||||
</p>
|
||||
|
||||
<H4><a name="Ocaml_nn26"></a>27.2.5.4 Creating director objects</H4>
|
||||
|
||||
|
||||
<p>
|
||||
The definition of the actual object triangle can be described this way:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
let triangle =
|
||||
new_derived_object
|
||||
new_shape
|
||||
(triangle_class ((0.0,0.0),(0.5,1.0),(1.0,0.0)))
|
||||
'()
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
The first argument to <tt>new_derived_object</tt>, new_shape is the method
|
||||
which returns a shape instance. This function will be invoked with the
|
||||
third argument will be appended to the argument list [ C_void ]. In the
|
||||
example, the actual argument list is sent as (C_list [ C_void ; C_void ]).
|
||||
The augmented constructor for a director class needs the first argument
|
||||
to determine whether it is being constructed as a derived object, or as
|
||||
an object of the indicated type only (in this case <tt>shape</tt>). The
|
||||
Second argument is a closure that will be added to the final C_obj.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The actual object passed to the self parameter of the director object will
|
||||
be a C_director_core, containing a c_obj option ref and a c_obj. The
|
||||
c_obj provided is the same object that will be returned from new_derived
|
||||
object, that is, the object exposing the overridden methods. The other part
|
||||
is an option ref that will have its value extracted before becoming the
|
||||
<tt>ob</tt> parameter of your class closure. This ref will contain
|
||||
<tt>None</tt> if the C++ object underlying is ever destroyed, and will
|
||||
consequently trigger an exception when any method is called on the object
|
||||
after that point (the actual raise is from an inner function used by
|
||||
new_derived_object, and throws NotObject). This prevents a deleted C++
|
||||
object from causing a core dump, as long as the object is destroyed
|
||||
properly.
|
||||
</p>
|
||||
|
||||
<H4><a name="Ocaml_nn27"></a>27.2.5.5 Typemaps for directors, <tt>directorin, directorout, directorargout</tt></H4>
|
||||
|
||||
|
||||
<p>
|
||||
Special typemaps exist for use with directors, the <tt>directorin, directorout, directorargout</tt>
|
||||
are used in place of <tt>in, out, argout</tt> typemaps, except that their
|
||||
direction is reversed. They provide for you to provide argout values, as
|
||||
well as a function return value in the same way you provide function arguments,
|
||||
and to receive arguments the same way you normally receive function returns.
|
||||
</p>
|
||||
|
||||
<H4><a name="Ocaml_nn28"></a>27.2.5.6 <tt>directorin</tt> typemap</H4>
|
||||
|
||||
|
||||
<p>
|
||||
The <tt>directorin</tt> typemap is used when you will receive arguments from a call
|
||||
made by C++ code to you, therefore, values will be translated from C++ to
|
||||
ocaml. You must provide some valid C_obj value. This is the value your ocaml
|
||||
code receives when you are called. In general, a simple <tt>directorin</tt> typemap
|
||||
can use the same body as a simple <tt>out</tt> typemap.
|
||||
</p>
|
||||
|
||||
<H4><a name="Ocaml_nn29"></a>27.2.5.7 <tt>directorout</tt> typemap</H4>
|
||||
|
||||
|
||||
<p>
|
||||
The <tt>directorout</tt> typemap is used when you will send an argument from your
|
||||
code back to the C++ caller. That is; directorout specifies a function return
|
||||
conversion. You can usually use the same body as an <tt>in</tt> typemap
|
||||
for the same type, except when there are special requirements for object
|
||||
ownership, etc.
|
||||
</p>
|
||||
|
||||
<H4><a name="Ocaml_nn30"></a>27.2.5.8 <tt>directorargout</tt> typemap</H4>
|
||||
|
||||
|
||||
<p>
|
||||
C++ allows function arguments which are by pointer (*) and by reference (&)
|
||||
to receive a value from the called function, as well as sending one there.
|
||||
Sometimes, this is the main purpose of the argument given. <tt>directorargout</tt>
|
||||
typemaps allow your caml code to emulate this by specifying additional return
|
||||
values to be put into the output parameters. The SWIG ocaml module is a bit
|
||||
loose in order to make code easier to write. In this case, your return to
|
||||
the caller must be a list containing the normal function return first, followed
|
||||
by any argout values in order. These argout values will be taken from the
|
||||
list and assigned to the values to be returned to C++ through directorargout typemaps.
|
||||
In the event that you don't specify all of the necessary values, integral
|
||||
values will read zero, and struct or object returns have undefined results.
|
||||
</p>
|
||||
|
||||
<H3><a name="Ocaml_nn31"></a>27.2.6 Exceptions</H3>
|
||||
|
||||
|
||||
<p>
|
||||
Catching exceptions is now supported using SWIG's %exception feature. A simple
|
||||
but not too useful example is provided by the throw_exception testcase in
|
||||
Examples/test-suite. You can provide your own exceptions, too.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
844
Doc/Manual/Octave.html
Normal file
844
Doc/Manual/Octave.html
Normal file
|
|
@ -0,0 +1,844 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and Octave</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
</head>
|
||||
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
|
||||
<H1><a name="Octave"></a>28 SWIG and Octave</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_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>
|
||||
<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.octave.org">www.octave.org</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"></a>28.1 Preliminaries</H2>
|
||||
|
||||
|
||||
<p>
|
||||
The SWIG implemention was first based on Octave 2.9.12, so this is the minimum version required. Testing has only been done on Linux.
|
||||
</p>
|
||||
|
||||
<H2><a name="Octave_nn3"></a>28.2 Running SWIG</H2>
|
||||
|
||||
|
||||
<p>
|
||||
Let's start with a very simple SWIG interface file, example.i:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%module example
|
||||
%{
|
||||
#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 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++ example.i </pre></div>
|
||||
|
||||
<p>
|
||||
This creates a C++ source file <tt>example_wrap.cxx</tt>. 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>
|
||||
|
||||
<p>
|
||||
The swig command line has a number of options you can use, like to redirect it's output. Use <tt>swig --help</tt> to learn about these.
|
||||
</p>
|
||||
|
||||
<H3><a name="Octave_nn5"></a>28.2.1 Compiling a dynamic module</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++ example.i -o example_wrap.cxx
|
||||
$ mkoctfile example_wrap.cxx 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 example.oct, which contains the compiled extension module. Loading it into Octave is then a matter of invoking
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>octave:1> example</pre></div>
|
||||
|
||||
<H3><a name="Octave_nn6"></a>28.2.2 Using your module</H3>
|
||||
|
||||
|
||||
<p>
|
||||
Assuming all goes well, you will be able to do this:
|
||||
<br>
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>$ octave -q
|
||||
octave:1> example
|
||||
octave:2> example.gcd(4,6)
|
||||
ans = 2
|
||||
octave:3> example.cvar.Foo
|
||||
ans = 3
|
||||
octave:4> example.cvar.Foo=4;
|
||||
octave:5> example.cvar.Foo
|
||||
ans = 4 </pre></div>
|
||||
|
||||
<H2><a name="Octave_nn7"></a>28.3 A tour of basic C/C++ wrapping</H2>
|
||||
|
||||
|
||||
<H3><a name="Octave_nn8"></a>28.3.1 Modules</H3>
|
||||
|
||||
|
||||
<p>
|
||||
The SWIG module directive specifies the name of the Octave module. If you specify `module example', then in Octave everything in the module will be accessible under "example", 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>example</tt>, it will try to find the .m or .oct file that defines the function "example". It will thusly find example.oct, that upon loading will register all of the module's symbols.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Giving this function a parameter "global" will cause it to load all symbols into the global namespace in addition to the <tt>example</tt> namespace. For example:
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>$ octave -q
|
||||
octave:1> example("global")
|
||||
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>
|
||||
It is also possible to rename the module namespace with an assignment, as in: <br>
|
||||
<div class="targetlang"><pre>octave:1> example;
|
||||
octave:2> c=example;
|
||||
octave:3> c.gcd(10,4)
|
||||
ans = 2 </pre></div>
|
||||
|
||||
<p>
|
||||
All global variables are put into the cvar namespace object. This is accessible either as <tt>my_module.cvar</tt>, or just <tt>cvar</tt> (if the module is imported into the global namespace).
|
||||
</p>
|
||||
<p>
|
||||
One can also rename it by simple assignment, e.g.,
|
||||
</p>
|
||||
<div class="targetlang"><pre>
|
||||
octave:1> some_vars = cvar;
|
||||
</pre></div>
|
||||
|
||||
<H3><a name="Octave_nn9"></a>28.3.2 Functions</H3>
|
||||
|
||||
|
||||
<p>
|
||||
Global functions are wrapped as new Octave built-in functions. For example,
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>%module example
|
||||
int fact(int n); </pre></div>
|
||||
|
||||
<p>
|
||||
creates a built-in function <tt>example.fact(n)</tt> that works exactly like you think it does:
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>octave:1> example.fact(4)
|
||||
24 </pre></div>
|
||||
|
||||
<H3><a name="Octave_nn10"></a>28.3.3 Global variables</H3>
|
||||
|
||||
|
||||
<p>
|
||||
Global variables are a little special in Octave. Given a global variable:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>%module example
|
||||
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> example;
|
||||
octave:2> c=example.cvar.Foo
|
||||
c = 3
|
||||
octave:3> example.cvar.Foo=4;
|
||||
octave:4> c
|
||||
c = 3
|
||||
octave:5> example.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 example
|
||||
%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> example
|
||||
octave:2> example.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> example;
|
||||
octave:2> example.PI=3.142;
|
||||
octave:3> example.PI
|
||||
ans = 3.1420 </pre></div>
|
||||
|
||||
<H3><a name="Octave_nn11"></a>28.3.4 Constants and enums</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 example
|
||||
%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>example.ICONST=42
|
||||
example.SCONST="Hello World"
|
||||
example.SUNDAY=0
|
||||
.... </pre></div>
|
||||
|
||||
<H3><a name="Octave_nn12"></a>28.3.5 Pointers</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 example
|
||||
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> example;
|
||||
octave:2> f=example.fopen("w","junk");
|
||||
octave:3> example.fputs("Hello world",f);
|
||||
octave:4> example.fclose(f);
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Simply printing the value of a wrapped C++ type will print it's typename. E.g.,
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>octave:1> example;
|
||||
octave:2> f=example.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> example;
|
||||
octave:2> f=example.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"></a>28.3.6 Structures and C++ classes</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> example;
|
||||
octave:2> p=example.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> example;
|
||||
octave:2> p1=example.Point(3,5);
|
||||
octave:3> p2=example.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"></a>28.3.7 C++ inheritance</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"></a>28.3.8 C++ overloaded functions</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"></a>28.3.9 C++ operators</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>
|
||||
|
||||
<H3><a name="Octave_nn19"></a>28.3.10 Class extension with %extend</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>
|
||||
<H3><a name="Octave_nn20"></a>28.3.11 C++ templates</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 example
|
||||
%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 example
|
||||
%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"></a>28.3.12 C++ Smart Pointers</H3>
|
||||
|
||||
|
||||
<p>
|
||||
C++ smart pointers are fully supported as in other modules.
|
||||
</p>
|
||||
|
||||
<H3><a name="Octave_nn22"></a>28.3.13 Directors (calling Octave from C++ code)</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"></a>28.3.14 Threads</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"></a>28.3.15 Memory management</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"></a>28.3.16 STL support</H3>
|
||||
|
||||
|
||||
<p>
|
||||
Various STL library files are provided for wrapping STL containers.
|
||||
</p>
|
||||
|
||||
<H3><a name="Octave_nn26"></a>28.3.17 Matrix typemaps</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>
|
||||
3001
Doc/Manual/Perl5.html
Normal file
3001
Doc/Manual/Perl5.html
Normal file
File diff suppressed because it is too large
Load diff
1252
Doc/Manual/Php.html
Normal file
1252
Doc/Manual/Php.html
Normal file
File diff suppressed because it is too large
Load diff
245
Doc/Manual/Pike.html
Normal file
245
Doc/Manual/Pike.html
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and Pike</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<H1><a name="Pike"></a>31 SWIG and Pike</H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#Pike_nn2">Preliminaries</a>
|
||||
<ul>
|
||||
<li><a href="#Pike_nn3">Running SWIG</a>
|
||||
<li><a href="#Pike_nn4">Getting the right header files</a>
|
||||
<li><a href="#Pike_nn5">Using your module</a>
|
||||
</ul>
|
||||
<li><a href="#Pike_nn6">Basic C/C++ Mapping</a>
|
||||
<ul>
|
||||
<li><a href="#Pike_nn7">Modules</a>
|
||||
<li><a href="#Pike_nn8">Functions</a>
|
||||
<li><a href="#Pike_nn9">Global variables</a>
|
||||
<li><a href="#Pike_nn10">Constants and enumerated types</a>
|
||||
<li><a href="#Pike_nn11">Constructors and Destructors</a>
|
||||
<li><a href="#Pike_nn12">Static Members</a>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
This chapter describes SWIG support for Pike. As of this writing, the
|
||||
SWIG Pike module is still under development and is not considered
|
||||
ready for prime time. The Pike module is being developed against the
|
||||
Pike 7.4.10 release and may not be compatible with previous versions
|
||||
of Pike.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This chapter covers most SWIG features, but certain low-level details
|
||||
are covered in less depth than in earlier chapters. At the very
|
||||
least, make sure you read the "<a href="SWIG.html#SWIG">SWIG Basics</a>"
|
||||
chapter.<br>
|
||||
</p>
|
||||
|
||||
<H2><a name="Pike_nn2"></a>31.1 Preliminaries</H2>
|
||||
|
||||
|
||||
<H3><a name="Pike_nn3"></a>31.1.1 Running SWIG</H3>
|
||||
|
||||
|
||||
<p>
|
||||
Suppose that you defined a SWIG module such as the following:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>%module example<br><br>%{<br>#include "example.h"<br>%}<br><br>int fact(int n);<br></pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
To build a C extension module for Pike, run SWIG using the <tt>-pike</tt> option :
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>$ <b>swig -pike example.i</b><br></pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
If you're building a C++ extension, be sure to add the <tt>-c++</tt> option:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>$ <b>swig -c++ -pike example.i</b><br></pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
This creates a single source file named <tt>example_wrap.c</tt> (or <tt>example_wrap.cxx</tt>, if you
|
||||
ran SWIG with the <tt>-c++</tt> option).
|
||||
The SWIG-generated 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 <tt>example.i</tt>, the name
|
||||
of the wrapper file is <tt>example_wrap.c</tt>. To change this, you
|
||||
can use the <tt>-o</tt> option:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>$ <b>swig -pike -o pseudonym.c example.i</b><br></pre>
|
||||
</div>
|
||||
<H3><a name="Pike_nn4"></a>31.1.2 Getting the right header files</H3>
|
||||
|
||||
|
||||
<p>
|
||||
In order to compile the C/C++ wrappers, the compiler needs to know the
|
||||
path to the Pike header files. These files are usually contained in a
|
||||
directory such as
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>/usr/local/pike/7.4.10/include/pike<br></pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
There doesn't seem to be any way to get Pike itself to reveal the
|
||||
location of these files, so you may need to hunt around for them.
|
||||
You're looking for files with the names <tt>global.h</tt>, <tt>program.h</tt>
|
||||
and so on.
|
||||
</p>
|
||||
|
||||
<H3><a name="Pike_nn5"></a>31.1.3 Using your module</H3>
|
||||
|
||||
|
||||
<p>
|
||||
To use your module, simply use Pike's <tt>import</tt> statement:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
$ <b>pike</b>
|
||||
Pike v7.4 release 10 running Hilfe v3.5 (Incremental Pike Frontend)
|
||||
> <b>import example;</b>
|
||||
> <b>fact(4);</b>
|
||||
(1) Result: 24
|
||||
</pre></div>
|
||||
|
||||
<H2><a name="Pike_nn6"></a>31.2 Basic C/C++ Mapping</H2>
|
||||
|
||||
|
||||
<H3><a name="Pike_nn7"></a>31.2.1 Modules</H3>
|
||||
|
||||
|
||||
<p>
|
||||
All of the code for a given SWIG module is wrapped into a single Pike
|
||||
module. Since the name of the shared library that implements your
|
||||
module ultimately determines the module's name (as far as Pike is
|
||||
concerned), SWIG's <tt>%module</tt> directive doesn't really have any
|
||||
significance.
|
||||
</p>
|
||||
|
||||
<H3><a name="Pike_nn8"></a>31.2.2 Functions</H3>
|
||||
|
||||
|
||||
<p>
|
||||
Global functions are wrapped as new Pike built-in functions. For
|
||||
example,
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%module example
|
||||
|
||||
int fact(int n);
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
creates a new built-in function <tt>example.fact(n)</tt> that works
|
||||
exactly as you'd expect it to:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
> <b>import example;</b>
|
||||
> <b>fact(4);</b>
|
||||
(1) Result: 24
|
||||
</pre></div>
|
||||
|
||||
<H3><a name="Pike_nn9"></a>31.2.3 Global variables</H3>
|
||||
|
||||
|
||||
<p>
|
||||
Global variables are currently wrapped as a pair of functions, one to get
|
||||
the current value of the variable and another to set it. For example, the
|
||||
declaration
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%module example
|
||||
|
||||
double Foo;
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
will result in two functions, <tt>Foo_get()</tt> and <tt>Foo_set()</tt>:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
> <b>import example;</b>
|
||||
> <b>Foo_get();</b>
|
||||
(1) Result: 3.000000
|
||||
> <b>Foo_set(3.14159);</b>
|
||||
(2) Result: 0
|
||||
> <b>Foo_get();</b>
|
||||
(3) Result: 3.141590
|
||||
</pre></div>
|
||||
|
||||
<H3><a name="Pike_nn10"></a>31.2.4 Constants and enumerated types</H3>
|
||||
|
||||
|
||||
<p>
|
||||
Enumerated types in C/C++ declarations are wrapped as Pike constants,
|
||||
not as Pike enums.
|
||||
</p>
|
||||
|
||||
<H3><a name="Pike_nn11"></a>31.2.5 Constructors and Destructors</H3>
|
||||
|
||||
|
||||
<p>
|
||||
Constructors are wrapped as <tt>create()</tt> methods, and destructors are
|
||||
wrapped as <tt>destroy()</tt> methods, for Pike classes.
|
||||
</p>
|
||||
|
||||
<H3><a name="Pike_nn12"></a>31.2.6 Static Members</H3>
|
||||
|
||||
|
||||
<p>
|
||||
Since Pike doesn't support static methods or data for Pike classes, static
|
||||
member functions in your C++ classes are wrapped as regular functions and
|
||||
static member variables are wrapped as pairs of functions (one to get the
|
||||
value of the static member variable, and another to set it). The names of
|
||||
these functions are prepended with the name of the class.
|
||||
For example, given this C++ class declaration:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
class Shape
|
||||
{
|
||||
public:
|
||||
static void print();
|
||||
static int nshapes;
|
||||
};
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
SWIG will generate a <tt>Shape_print()</tt> method that invokes the static
|
||||
<tt>Shape::print()</tt> member function, as well as a pair of methods,
|
||||
<tt>Shape_nshapes_get()</tt> and <tt>Shape_nshapes_set()</tt>, to get and set
|
||||
the value of <tt>Shape::nshapes</tt>.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
219
Doc/Manual/Preface.html
Normal file
219
Doc/Manual/Preface.html
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Preface</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<H1><a name="Preface"></a>1 Preface</H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#Preface_nn2">Introduction</a>
|
||||
<li><a href="#Preface_nn4">SWIG Versions</a>
|
||||
<li><a href="#Preface_nn5">SWIG resources</a>
|
||||
<li><a href="#Preface_nn6">Prerequisites</a>
|
||||
<li><a href="#Preface_nn7">Organization of this manual</a>
|
||||
<li><a href="#Preface_nn8">How to avoid reading the manual</a>
|
||||
<li><a href="#Preface_nn9">Backwards compatibility</a>
|
||||
<li><a href="#Preface_nn10">Credits</a>
|
||||
<li><a href="#Preface_nn11">Bug reports</a>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<H2><a name="Preface_nn2"></a>1.1 Introduction</H2>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG (Simplified Wrapper and Interface Generator) is a software development tool for building scripting language
|
||||
interfaces to C and C++ programs. Originally developed in 1995, SWIG was
|
||||
first used by scientists in the Theoretical Physics Division at Los Alamos National Laboratory for
|
||||
building user interfaces to simulation codes running on the Connection
|
||||
Machine 5 supercomputer. In this environment, scientists needed to
|
||||
work with huge amounts of simulation data, complex hardware, and a
|
||||
constantly changing code base. The use of a scripting language
|
||||
interface provided a simple yet highly flexible foundation for solving these
|
||||
types of problems. SWIG simplifies development by largely automating
|
||||
the task of scripting language integration--allowing developers and users
|
||||
to focus on more important problems.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Although SWIG was originally developed for scientific applications, it
|
||||
has since evolved into a general purpose tool that is used in a wide
|
||||
variety of applications--in fact almost anything where C/C++ programming
|
||||
is involved.
|
||||
|
||||
<H2><a name="Preface_nn4"></a>1.2 SWIG Versions</H2>
|
||||
|
||||
|
||||
<p>
|
||||
In the late 1990's, the most stable version of SWIG was release
|
||||
1.1p5. Versions 1.3.x were officially development versions and these were released
|
||||
over a period of 10 years starting from the year 2000. The final version in the 1.3.x
|
||||
series was 1.3.40, but in truth the 1.3.x series had been stable for many years.
|
||||
An official stable version was released along with the decision to make SWIG
|
||||
license changes and this gave rise to version 2.0.0 in 2010. The license was clarified
|
||||
so that the code that SWIG generated could be distributed
|
||||
under license terms of the user's choice/requirements and at the same time the SWIG
|
||||
source was placed under the GNU General Public License version 3.
|
||||
</p>
|
||||
|
||||
<H2><a name="Preface_nn5"></a>1.3 SWIG resources</H2>
|
||||
|
||||
|
||||
<p>
|
||||
The official location of SWIG related material is
|
||||
</p>
|
||||
|
||||
<div class="shell"><pre>
|
||||
<a href="http://www.swig.org">http://www.swig.org</a>
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
This site contains the latest version of the software, users guide,
|
||||
and information regarding bugs, installation problems, and
|
||||
implementation tricks.
|
||||
|
||||
<p>
|
||||
You can also subscribe to the swig-user mailing list by visiting the page
|
||||
</p>
|
||||
|
||||
<div class="shell"><pre>
|
||||
<a href="http://www.swig.org/mail.html">http://www.swig.org/mail.html</a>
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
The mailing list often discusses some of the more technical aspects of
|
||||
SWIG along with information about beta releases and future work.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Subversion access to the latest version of SWIG is also available. More information
|
||||
about this can be obtained at:
|
||||
</p>
|
||||
|
||||
<div class="shell"><pre>
|
||||
<a href="http://www.swig.org/svn.html">http://www.swig.org/svn.html</a>
|
||||
</pre></div>
|
||||
|
||||
|
||||
<H2><a name="Preface_nn6"></a>1.4 Prerequisites</H2>
|
||||
|
||||
|
||||
<p>
|
||||
This manual assumes that you know how to write C/C++ programs and that you
|
||||
have at least heard of scripting languages such as
|
||||
Tcl, Python, and Perl. A detailed knowledge of these scripting
|
||||
languages is not required although some familiarity won't
|
||||
hurt. No prior experience with building C extensions to these
|
||||
languages is required---after all, this is what SWIG does automatically.
|
||||
However, you should be reasonably familiar with the use of
|
||||
compilers, linkers, and makefiles since making
|
||||
scripting language extensions is somewhat more complicated than
|
||||
writing a normal C program.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Over time SWIG releases have become significantly more capable in
|
||||
their C++ handling--especially support for advanced features like
|
||||
namespaces, overloaded operators, and templates. Whenever possible,
|
||||
this manual tries to cover the technicalities of this interface.
|
||||
However, this isn't meant to be a tutorial on C++ programming. For many
|
||||
of the gory details, you will almost certainly want to consult a good C++ reference. If you don't program
|
||||
in C++, you may just want to skip those parts of the manual.
|
||||
|
||||
<H2><a name="Preface_nn7"></a>1.5 Organization of this manual</H2>
|
||||
|
||||
|
||||
<p>
|
||||
The first few chapters of this manual describe SWIG in general and
|
||||
provide an overview of its capabilities. The remaining chapters are
|
||||
devoted to specific SWIG language modules and are self
|
||||
contained. Thus, if you are using SWIG to build Python interfaces, you
|
||||
can probably skip to that chapter and find almost everything you need
|
||||
to know.
|
||||
</p>
|
||||
|
||||
<H2><a name="Preface_nn8"></a>1.6 How to avoid reading the manual</H2>
|
||||
|
||||
|
||||
<p>
|
||||
If you hate reading manuals, glance at the "Introduction" which
|
||||
contains a few simple examples. These
|
||||
examples contain about 95% of everything you need to know to use
|
||||
SWIG. After that, simply use the language-specific chapters as a reference.
|
||||
The SWIG distribution also comes with a large directory of
|
||||
examples that illustrate different topics.
|
||||
</p>
|
||||
|
||||
<H2><a name="Preface_nn9"></a>1.7 Backwards compatibility</H2>
|
||||
|
||||
|
||||
<p>
|
||||
If you are a previous user of SWIG, don't expect
|
||||
SWIG to provide complete backwards compatibility.
|
||||
Although the developers strive to the utmost to keep backwards compatibility,
|
||||
this isn't always possible as the
|
||||
primary goal over time is to make SWIG
|
||||
better---a process that would simply be impossible if the developers
|
||||
are constantly bogged down with backwards compatibility issues.
|
||||
Potential incompatibilities are clearly marked in the detailed release notes
|
||||
(CHANGES files).
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
If you need to work with different versions of SWIG and backwards
|
||||
compatibility is an issue, you can use the SWIG_VERSION preprocessor
|
||||
symbol which holds the version of SWIG being executed.
|
||||
SWIG_VERSION is a hexadecimal integer such as 0x010311 (corresponding to SWIG-1.3.11).
|
||||
This can be used in an interface file to define different typemaps, take
|
||||
advantage of different features etc:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
#if SWIG_VERSION >= 0x010311
|
||||
/* Use some fancy new feature */
|
||||
#endif
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Note: The version symbol is not defined in the generated SWIG
|
||||
wrapper file. The SWIG preprocessor has defined SWIG_VERSION since SWIG-1.3.11.
|
||||
</p>
|
||||
|
||||
<H2><a name="Preface_nn10"></a>1.8 Credits</H2>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG is an unfunded project that would not be possible without the
|
||||
contributions of many people working in their spare time.
|
||||
If you have benefitted from using SWIG, please consider
|
||||
<a href="http://www.swig.org/donate.html">Donating to SWIG</a> to keep development going.
|
||||
There have been a large varied number of people
|
||||
who have made contributions at all levels over time. Contributors
|
||||
are mentioned either in the COPYRIGHT file or CHANGES files shipped with SWIG or in submitted bugs.
|
||||
</p>
|
||||
|
||||
<H2><a name="Preface_nn11"></a>1.9 Bug reports</H2>
|
||||
|
||||
|
||||
<p>
|
||||
Although every attempt has been made to make SWIG bug-free, we are also trying
|
||||
to make feature improvements that may introduce bugs.
|
||||
To report a bug, either send mail to the SWIG developer
|
||||
list at the <a href="http://www.swig.org/mail.html">swig-devel mailing list</a> or report a bug
|
||||
at the <a href="http://www.swig.org/bugs.html">SWIG bug tracker</a>. In your report, be as specific as
|
||||
possible, including (if applicable), error messages, tracebacks (if a
|
||||
core dump occurred), corresponding portions of the SWIG interface file
|
||||
used, and any important pieces of the SWIG generated wrapper code. We
|
||||
can only fix bugs if we know about them.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
489
Doc/Manual/Preprocessor.html
Normal file
489
Doc/Manual/Preprocessor.html
Normal file
|
|
@ -0,0 +1,489 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG Preprocessor</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<H1><a name="Preprocessor"></a>7 Preprocessing</H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#Preprocessor_nn2">File inclusion</a>
|
||||
<li><a href="#Preprocessor_nn3">File imports</a>
|
||||
<li><a href="#Preprocessor_condition_compilation">Conditional Compilation</a>
|
||||
<li><a href="#Preprocessor_nn5">Macro Expansion</a>
|
||||
<li><a href="#Preprocessor_nn6">SWIG Macros</a>
|
||||
<li><a href="#Preprocessor_nn7">C99 and GNU Extensions</a>
|
||||
<li><a href="#Preprocessor_nn8">Preprocessing and %{ ... %} & " ... " delimiters</a>
|
||||
<li><a href="#Preprocessor_nn9">Preprocessing and { ... } delimiters</a>
|
||||
<li><a href="#Preprocessor_typemap_delimiters">Preprocessor and Typemaps</a>
|
||||
<li><a href="#Preprocessor_nn10">Viewing preprocessor output</a>
|
||||
<li><a href="#Preprocessor_warning_error">The #error and #warning directives</a>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
SWIG includes its own enhanced version of the C preprocessor. The preprocessor
|
||||
supports the standard preprocessor directives and macro expansion rules.
|
||||
However, a number of modifications and enhancements have been made. This
|
||||
chapter describes some of these modifications.
|
||||
</p>
|
||||
|
||||
<H2><a name="Preprocessor_nn2"></a>7.1 File inclusion</H2>
|
||||
|
||||
|
||||
<p>
|
||||
To include another file into a SWIG interface, use the <tt>%include</tt> directive
|
||||
like this:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%include "pointer.i"
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Unlike, <tt>#include</tt>, <tt>%include</tt> includes each file once (and will not
|
||||
reload the file on subsequent <tt>%include</tt> declarations). Therefore, it
|
||||
is not necessary to use include-guards in SWIG interfaces.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
By default, the <tt>#include</tt> is ignored unless you run SWIG with the
|
||||
<tt>-includeall</tt> option. The reason for ignoring traditional includes
|
||||
is that you often don't want SWIG to try and wrap everything included
|
||||
in standard header system headers and auxiliary files.
|
||||
|
||||
<H2><a name="Preprocessor_nn3"></a>7.2 File imports</H2>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG provides another file inclusion directive with the <tt>%import</tt> directive.
|
||||
For example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%import "foo.i"
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The purpose of <tt>%import</tt> is to collect certain information from another
|
||||
SWIG interface file or a header file without actually generating any wrapper code.
|
||||
Such information generally includes type declarations (e.g., <tt>typedef</tt>) as well as
|
||||
C++ classes that might be used as base-classes for class declarations in the interface.
|
||||
The use of <tt>%import</tt> is also important when SWIG is used to generate
|
||||
extensions as a collection of related modules. This is an advanced topic and is described
|
||||
in later in the <a href="Modules.html#Modules">Working with Modules</a> chapter.
|
||||
</p>
|
||||
|
||||
<P>
|
||||
The <tt>-importall</tt> directive tells SWIG to follow all <tt>#include</tt> statements
|
||||
as imports. This might be useful if you want to extract type definitions from system
|
||||
header files without generating any wrappers.
|
||||
|
||||
<H2><a name="Preprocessor_condition_compilation"></a>7.3 Conditional Compilation</H2>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG fully supports the use of <tt>#if</tt>, <tt>#ifdef</tt>,
|
||||
<tt>#ifndef</tt>, <tt>#else</tt>, <tt>#endif</tt> to conditionally
|
||||
include parts of an interface. The following symbols are predefined
|
||||
by SWIG when it is parsing the interface:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
SWIG Always defined when SWIG is processing a file
|
||||
SWIGIMPORTED Defined when SWIG is importing a file with <tt>%import</tt>
|
||||
SWIG_VERSION Hexadecimal (binary-coded decimal) number containing SWIG version,
|
||||
such as 0x010311 (corresponding to SWIG-1.3.11).
|
||||
|
||||
SWIGALLEGROCL Defined when using Allegro CL
|
||||
SWIGCFFI Defined when using CFFI
|
||||
SWIGCHICKEN Defined when using CHICKEN
|
||||
SWIGCLISP Defined when using CLISP
|
||||
SWIGCSHARP Defined when using C#
|
||||
SWIGGUILE Defined when using Guile
|
||||
SWIGJAVA Defined when using Java
|
||||
SWIGLUA Defined when using Lua
|
||||
SWIGMODULA3 Defined when using Modula-3
|
||||
SWIGMZSCHEME Defined when using Mzscheme
|
||||
SWIGOCAML Defined when using Ocaml
|
||||
SWIGOCTAVE Defined when using Octave
|
||||
SWIGPERL Defined when using Perl
|
||||
SWIGPHP Defined when using PHP
|
||||
SWIGPIKE Defined when using Pike
|
||||
SWIGPYTHON Defined when using Python
|
||||
SWIGR Defined when using R
|
||||
SWIGRUBY Defined when using Ruby
|
||||
SWIGSEXP Defined when using S-expressions
|
||||
SWIGTCL Defined when using Tcl
|
||||
SWIGXML Defined when using XML
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
In addition, SWIG defines the following set of standard C/C++ macros:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
__LINE__ Current line number
|
||||
__FILE__ Current file name
|
||||
__STDC__ Defined to indicate ANSI C
|
||||
__cplusplus Defined when -c++ option used
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Interface files can look at these symbols as necessary to change the
|
||||
way in which an interface is generated or to mix SWIG directives with
|
||||
C code. These symbols are also defined within the C code generated by
|
||||
SWIG (except for the symbol `<tt>SWIG</tt>' which is only defined
|
||||
within the SWIG compiler).
|
||||
</p>
|
||||
|
||||
<H2><a name="Preprocessor_nn5"></a>7.4 Macro Expansion</H2>
|
||||
|
||||
|
||||
<p>
|
||||
Traditional preprocessor macros can be used in SWIG interfaces. Be aware that the <tt>#define</tt> statement
|
||||
is also used to try and detect constants. Therefore, if you have something like this in your file,
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
#ifndef _FOO_H 1
|
||||
#define _FOO_H 1
|
||||
...
|
||||
#endif
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
you may get some extra constants such as <tt>_FOO_H</tt> showing up in the scripting interface.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
More complex macros can be defined in the standard way. For example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
#define EXTERN extern
|
||||
#ifdef __STDC__
|
||||
#define _ANSI(args) (args)
|
||||
#else
|
||||
#define _ANSI(args) ()
|
||||
#endif
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The following operators can appear in macro definitions:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><tt>#x</tt><br>
|
||||
Converts macro argument <tt>x</tt> to a string surrounded by double quotes ("x").
|
||||
</li>
|
||||
|
||||
<li><tt>x ## y</tt><br>
|
||||
Concatenates x and y together to form <tt>xy</tt>.
|
||||
</li>
|
||||
|
||||
<li><tt>`x`</tt><br>
|
||||
If <tt>x</tt> is a string surrounded by double quotes, do nothing. Otherwise, turn into a string
|
||||
like <tt>#x</tt>. This is a non-standard SWIG extension.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<H2><a name="Preprocessor_nn6"></a>7.5 SWIG Macros</H2>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG provides an enhanced macro capability with the <tt>%define</tt> and <tt>%enddef</tt> directives.
|
||||
For example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%define ARRAYHELPER(type,name)
|
||||
%inline %{
|
||||
type *new_ ## name (int nitems) {
|
||||
return (type *) malloc(sizeof(type)*nitems);
|
||||
}
|
||||
void delete_ ## name(type *t) {
|
||||
free(t);
|
||||
}
|
||||
type name ## _get(type *t, int index) {
|
||||
return t[index];
|
||||
}
|
||||
void name ## _set(type *t, int index, type val) {
|
||||
t[index] = val;
|
||||
}
|
||||
%}
|
||||
%enddef
|
||||
|
||||
ARRAYHELPER(int, IntArray)
|
||||
ARRAYHELPER(double, DoubleArray)
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The primary purpose of <tt>%define</tt> is to define large macros of code. Unlike normal C preprocessor
|
||||
macros, it is not necessary to terminate each line with a continuation character (\)--the macro definition
|
||||
extends to the first occurrence of <tt>%enddef</tt>. Furthermore, when such macros are expanded,
|
||||
they are reparsed through the C preprocessor. Thus, SWIG macros can contain all other preprocessor
|
||||
directives except for nested <tt>%define</tt> statements.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The SWIG macro capability is a very quick and easy way to generate large amounts of code. In fact,
|
||||
many of SWIG's advanced features and libraries are built using this mechanism (such as C++ template
|
||||
support).
|
||||
</p>
|
||||
|
||||
<H2><a name="Preprocessor_nn7"></a>7.6 C99 and GNU Extensions</H2>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG-1.3.12 and newer releases support variadic preprocessor macros. For example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
#define DEBUGF(fmt,...) fprintf(stderr,fmt,__VA_ARGS__)
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
When used, any extra arguments to <tt>...</tt> are placed into the
|
||||
special variable <tt>__VA_ARGS__</tt>. This also works with special SWIG
|
||||
macros defined using <tt>%define</tt>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
SWIG allows a variable number of arguments to be empty. However, this often results
|
||||
in an extra comma (,) and syntax error in the resulting expansion. For example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
DEBUGF("hello"); --> fprintf(stderr,"hello",);
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
To get rid of the extra comma, use <tt>##</tt> like this:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
#define DEBUGF(fmt,...) fprintf(stderr,fmt, ##__VA_ARGS__)
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
SWIG also supports GNU-style variadic macros. For example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
#define DEBUGF(fmt, args...) fprintf(stdout,fmt,args)
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<b>Comment:</b> It's not entirely clear how variadic macros might be useful to
|
||||
interface building. However, they are used internally to implement a number of
|
||||
SWIG directives and are provided to make SWIG more compatible with C99 code.
|
||||
</p>
|
||||
|
||||
<H2><a name="Preprocessor_nn8"></a>7.7 Preprocessing and %{ ... %} & " ... " delimiters</H2>
|
||||
|
||||
|
||||
<p>
|
||||
The SWIG preprocessor does not process any text enclosed in a code block %{ ... %}. Therefore,
|
||||
if you write code like this,
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%{
|
||||
#ifdef NEED_BLAH
|
||||
int blah() {
|
||||
...
|
||||
}
|
||||
#endif
|
||||
%}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
the contents of the <tt>%{ ... %}</tt> block are copied without
|
||||
modification to the output (including all preprocessor directives).
|
||||
</p>
|
||||
|
||||
<H2><a name="Preprocessor_nn9"></a>7.8 Preprocessing and { ... } delimiters</H2>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG always runs the preprocessor on text appearing inside <tt>{ ... }</tt>. However,
|
||||
sometimes it is desirable to make a preprocessor directive pass through to the output
|
||||
file. For example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%extend Foo {
|
||||
void bar() {
|
||||
#ifdef DEBUG
|
||||
printf("I'm in bar\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
By default, SWIG will interpret the <tt>#ifdef DEBUG</tt> statement. However, if you really wanted that code
|
||||
to actually go into the wrapper file, prefix the preprocessor directives with <tt>%</tt> like this:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%extend Foo {
|
||||
void bar() {
|
||||
%#ifdef DEBUG
|
||||
printf("I'm in bar\n");
|
||||
%#endif
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
SWIG will strip the extra <tt>%</tt> and leave the preprocessor directive in the code.
|
||||
</p>
|
||||
|
||||
<H2><a name="Preprocessor_typemap_delimiters"></a>7.9 Preprocessor and Typemaps</H2>
|
||||
|
||||
|
||||
<p>
|
||||
<a href="Typemaps.html#Typemaps">Typemaps</a> support a special attribute called <tt>noblock</tt> where the { ... } delimiters can be used,
|
||||
but the delimiters are not actually generated into the code.
|
||||
The effect is then similar to using "" or %{ %} delimiters but the code <b>is</b> run through the preprocessor. For example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
#define SWIG_macro(CAST) (CAST)$input
|
||||
%typemap(in) Int {$1= SWIG_macro(int);}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
might generate
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
{
|
||||
arg1=(int)jarg1;
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
whereas
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
#define SWIG_macro(CAST) (CAST)$input
|
||||
%typemap(in,noblock=1) Int {$1= SWIG_macro(int);}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
might generate
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
arg1=(int)jarg1;
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
and
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
#define SWIG_macro(CAST) (CAST)$input
|
||||
%typemap(in) Int %{$1=SWIG_macro(int);%}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
would generate
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
arg1=SWIG_macro(int);
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
|
||||
<H2><a name="Preprocessor_nn10"></a>7.10 Viewing preprocessor output</H2>
|
||||
|
||||
|
||||
<p>
|
||||
Like many compilers, SWIG supports a <tt>-E</tt> command line option to display the output from the preprocessor.
|
||||
When the <tt>-E</tt> switch is used, SWIG will not generate any wrappers.
|
||||
Instead the results after the preprocessor has run are displayed.
|
||||
This might be useful as an aid to debugging and viewing the results of macro expansions.
|
||||
</p>
|
||||
|
||||
<H2><a name="Preprocessor_warning_error"></a>7.11 The #error and #warning directives</H2>
|
||||
|
||||
|
||||
<p>
|
||||
SWIG supports the commonly used <tt>#warning</tt> and <tt>#error</tt> preprocessor directives.
|
||||
The <tt>#warning</tt> directive will cause SWIG to issue a warning then continue processing.
|
||||
The <tt>#error</tt> directive will cause SWIG to exit with a fatal error.
|
||||
Example usage:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
#error "This is a fatal error message"
|
||||
#warning "This is a warning message"
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The <tt>#error</tt> behaviour can be made to work like <tt>#warning</tt> if the <tt>-cpperraswarn</tt>
|
||||
commandline option is used. Alternatively, the <tt>#pragma</tt> directive can be used to the same effect, for example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
/* Modified behaviour: #error does not cause SWIG to exit with error */
|
||||
#pragma SWIG cpperraswarn=1
|
||||
/* Normal behaviour: #error does cause SWIG to exit with error */
|
||||
#pragma SWIG cpperraswarn=0
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
5182
Doc/Manual/Python.html
Normal file
5182
Doc/Manual/Python.html
Normal file
File diff suppressed because it is too large
Load diff
180
Doc/Manual/R.html
Normal file
180
Doc/Manual/R.html
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>SWIG and R</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<H1><a name="R"></a>33 SWIG and R</H1>
|
||||
<!-- INDEX -->
|
||||
<div class="sectiontoc">
|
||||
<ul>
|
||||
<li><a href="#R_nn2">Bugs</a>
|
||||
<li><a href="#R_nn3">Using R and SWIG</a>
|
||||
<li><a href="#R_nn4">Precompiling large R files</a>
|
||||
<li><a href="#R_nn5">General policy</a>
|
||||
<li><a href="#R_language_conventions">Language conventions</a>
|
||||
<li><a href="#R_nn6">C++ classes</a>
|
||||
<li><a href="#R_nn7">Enumerations</a>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
R is a GPL'ed open source statistical and plotting environment.
|
||||
Information about R can be found at <a
|
||||
href="http://www.r-project.org/">www.r-project.org</a>.
|
||||
|
||||
The R bindings are under active development. They have been used to
|
||||
compile and run an R interface to QuantLib running on Mandriva Linux
|
||||
with gcc. The R bindings also work on Microsoft Windows using Visual C++.
|
||||
</p>
|
||||
|
||||
<H2><a name="R_nn2"></a>33.1 Bugs</H2>
|
||||
|
||||
|
||||
<p>
|
||||
Currently the following features are not implemented or broken:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Garbage collection of created objects
|
||||
<li>C Array wrappings
|
||||
</ul>
|
||||
|
||||
<H2><a name="R_nn3"></a>33.2 Using R and SWIG</H2>
|
||||
|
||||
|
||||
<p>
|
||||
To use R and SWIG in C mode, execute the following commands where
|
||||
example.c is the name of the file with the functions in them
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
swig -r example.i
|
||||
R CMD SHLIB example_wrap.c example.c
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The corresponding options for C++ mode are
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
swig -c++ -r -o example_wrap.cpp example.i
|
||||
R CMD SHLIB example_wrap.cpp example.cpp
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Note that R is sensitive to the names of the files.
|
||||
The name of the wrapper file must be the
|
||||
name of the library unless you use the -o option to R when building the library, for example:
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
swig -c++ -r -o example_wrap.cpp example.i
|
||||
R CMD SHLIB -o example.so example_wrap.cpp example.cpp
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
R is also sensitive to the name of the file
|
||||
extension in C and C++ mode. In C++ mode, the file extension must be .cpp
|
||||
rather than .cxx for the R compile command to recognize it. If your C++ code is
|
||||
in a file using something other than a .cpp extension, then it may still work using PKG_LIBS:
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
swig -c++ -r -o example_wrap.cpp example.i
|
||||
PKG_LIBS="example.cxx" R CMD SHLIB -o example example_wrap.cpp
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The commands produces two files. A dynamic shared object file called
|
||||
example.so, or example.dll, and an R wrapper file called example.R. To load these
|
||||
files, start up R and type in the following commands
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
dyn.load(paste("example", .Platform$dynlib.ext, sep=""))
|
||||
source("example.R")
|
||||
cacheMetaData(1)
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
The cacheMetaData(1) will cause R to refresh its object tables.
|
||||
Without it, inheritance of wrapped objects may fail.
|
||||
|
||||
<p>
|
||||
These two files can be loaded in any order
|
||||
</p>
|
||||
|
||||
<H2><a name="R_nn4"></a>33.3 Precompiling large R files</H2>
|
||||
|
||||
|
||||
In cases where the R file is large, one make save a lot of loading
|
||||
time by precompiling the R wrapper. This can be done by creating the
|
||||
file makeRData.R which contains the following
|
||||
|
||||
<pre>
|
||||
source('BigFile.R')
|
||||
save(list=ls(all=TRUE),file="BigFile.RData", compress=TRUE)
|
||||
q(save="no")
|
||||
</pre>
|
||||
|
||||
This will generate a compiled R file called BigFile.RData that
|
||||
will save a large amount of loading time.
|
||||
|
||||
|
||||
|
||||
<H2><a name="R_nn5"></a>33.4 General policy</H2>
|
||||
|
||||
|
||||
<p>
|
||||
The general policy of the module is to treat the C/C++ as a basic
|
||||
wrapping over the underlying functions and rely on the R type system
|
||||
to provide R syntax.
|
||||
</p>
|
||||
|
||||
<H2><a name="R_language_conventions"></a>33.5 Language conventions</H2>
|
||||
|
||||
|
||||
<p>
|
||||
getitem and setitem use C++ conventions (i.e. zero based indices). [<-
|
||||
and [ are overloaded to allow for R syntax (one based indices and
|
||||
slices)
|
||||
</p>
|
||||
|
||||
<H2><a name="R_nn6"></a>33.6 C++ classes</H2>
|
||||
|
||||
|
||||
<p>
|
||||
C++ objects are implemented as external pointer objects with the class
|
||||
being the mangled name of the class. The C++ classes are encapsulated
|
||||
as an SEXP with an external pointer type. The class is the mangled
|
||||
name of the class. The nice thing about R is that is allows you to
|
||||
keep track of the pointer object which removes the necessity for a lot
|
||||
of the proxy class baggage you see in other languages.
|
||||
</p>
|
||||
|
||||
<H2><a name="R_nn7"></a>33.7 Enumerations</H2>
|
||||
|
||||
|
||||
<p>
|
||||
enumerations are characters which are then converted back and forth to
|
||||
ints before calling the C routines. All of the enumeration code is
|
||||
done in R.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
21
Doc/Manual/README
Normal file
21
Doc/Manual/README
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
This directory contains the HTML for the SWIG users manual.
|
||||
|
||||
All of this HTML is hand-written. However, section numbering, indices,
|
||||
and the table of contents is generated automatically by the 'maketoc.py'
|
||||
script. The Makefile has further information on how the various alternative
|
||||
forms of the documentation is generated from the hand-written HTML.
|
||||
|
||||
There are 4 types of boxes that code or whatever can be inside:
|
||||
- <div class="shell">...</div>
|
||||
This is for text that shows the output of running commands on the shell.
|
||||
- <div class="code">...</div>
|
||||
This is for either C, C++, or SWIG code
|
||||
- <div class="targetlang">...</div>
|
||||
This is for code in a target scripting language
|
||||
- <div class="diagram">...</div>
|
||||
This is for text that is not code or a shell
|
||||
|
||||
The general format is
|
||||
<div class="foo"><pre>
|
||||
whatever here
|
||||
</pre></div>
|
||||
10902
Doc/Manual/Ruby.html
Normal file
10902
Doc/Manual/Ruby.html
Normal file
File diff suppressed because it is too large
Load diff
3400
Doc/Manual/SWIG.html
Normal file
3400
Doc/Manual/SWIG.html
Normal file
File diff suppressed because it is too large
Load diff
5003
Doc/Manual/SWIGPlus.html
Normal file
5003
Doc/Manual/SWIGPlus.html
Normal file
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue