My first hack
So - we've built and run OO.o, and we want to prove to ourselves that
it is in fact possible to hack on it. So in a new terminal do this:
cd build/src680-m66
. ./LinuxX86Env.Set.sh
cd vcl
Now have a hack at vcl/source/window/menu.cxx (Menu::SetItemText);
(near line 1770) I suggest manually applying this change:
- pData->aText = rStr;
+ pData->aText = String(rStr).Reverse();
Then save. ( You can find more sensible things to hack in the
Tutorials )
You're still in vcl/ yes ? then type 'build debug=true'; wait for the scrolling text to stop; (5 seconds?). Now re-run
soffice -writer
. You should notice the effect in the menus.
If not, ensure the previous soffice.bin was dead with
killall -9 soffice.bin
Note: for day to day hacking you want to just run 'build'
inside the source tree. It is also highly recommended to work inside a
copy of the build tree, and generate / test patches in an un-hacked
version. To copy just the build/src680-m66 directory elsewhere, you
need to use the
relocate tool.
There is also documentation
here on it.
deliver, deliver.log and prj/d.lst
The syntax of d.lst is more comprehensible than build.lst, it omits
some default actions, such as copying build.lst into
inc/<module>/build.lst.
A line is of the form:
[action]: [arguments]
mkdir: %_DEST%\inc%_EXT%\external
where if '[action]:' is omitted, it defaults to the 'copy' action. Typical actions are
copy,
mkdir,
touch,
hedabu,
dos and
linklib.
The 'hedabu' action is particularly interesting, inasmuch that it
cosmetically re-formats the header to shrink it on install and adds the module name to the include path (
#include "my_header.hxx" becomes
#include <my_module/my_header.hxx>). Otherwise it's much like the copy action.
During the action, various macro variables are expanded some of which are:
- %__SRC% — distribution directory name eg. unxlngi4.pro</li>
- %_DEST% — absolute path into solver eg. /opt/OpenOffice/OOO_STABLE_1/solver/641/unxlngi4.pro
- %_EXT% — (unusual) way of having minor updates eg. 641.1, typically used to version every base sub-directory.
Typically then, if indeed you need to add a rule (cf. implicit directory copies), it will be of the form:
..\%__SRC%\inc\sal\*.h %_DEST%\inc%_EXT%\sal\*.h
NB. relative paths are relative to the 'prj/' directory.
Sometimes you might run into the situation where you'd like to
remove the delivered files from solver. Your configuration might have
changed and they are no longer needed. "deliver -delete" does just that,
however you might still need to delete "deliver.log" files manually as
well.
Can I get a char *
, please?
Just barely. OO.o has at least six string wrappers, although the C
implementations are of little interest:
-
rtl_String
— sal/inc/rtl/string.h
"Normal" string plus reference counting.
rtlstring-
>buffer
is useful, as is
rtlstring-
>length
. This object encapsulates
an generic 8bit string - of unknown encoding. Feel free to treat
rtlstring-
>buffer
as your beloved char *
.
If you really want to look at the implementation of some
rtl_String
function and lxr nor grep can help you, have
a look at sal/rtl/source/strtmpl.c.
-
OString
— sal/inc/rtl/string.hxx
Simply a rtl_String wrapped inside a class
; you
can use ostring.pData
to get at the rtl_String
(it's public). OString
has reasonably useful
methods for if you need them.
-
rtl_uString
— sal/inc/rtl/ustring.h
"Normal" Unicode string, similar to rtl_String, and
refcounted as well. However, this one always comes in UCS-2
encoding, presumably to be compatible with Java's
questionable choices.
See rtl_String
above to find where the implementation
of some rtl_uString
functions is hidden.
-
OUString
— sal/inc/rtl/ustring.hxx
An rtl_uString wrapped inside a class
. This is
what most of the OO.o code uses to pass strings around.
To convert an OString
to an OUString
it is necessary to specify the character set of the
OString
see; sal/inc/rtl/textenc.h
— the only interesting case is RTL_TEXTENCODING_UTF8
-
String
— tools/inc/string.hxx
This is an obsolete string class, aliased to 'UniString'.
It has a number of limitations such as a 64k length limit. You can have the buffer with GetBuffer()
, but it's Utf-16 encoded.
A couple of conversion functions are really useful here, particularly:
rtl::OString aOString = ::rtl::OUStringToOString (aOUString, RTL_TEXTENCODING_UTF8);
And the reverse:
rtl::OUString aOUString = ::rtl::OStringToOUString (aOString, RTL_TEXTENCODING_UTF8);
If you just want to programattically print out a string for debugging purposes you probably want define a macro like :
#define CHAR_POINTER(THE_OUSTRING) ::rtl::OUStringToOString (THE_OUSTRING, RTL_TEXTENCODING_UTF8).pData->buffer
and use it like :
printf ( "SvXMLNamespaceMap::AddIfKnown : %s / %s\n", CHAR_POINTER(rPrefix), CHAR_POINTER(rName) );
.
For the obsolete String class, aliased UniString, it's like :
printf ( "rGrfName : %s\n", ByteString( rGrfName, RTL_TEXTENCODING_UTF8).GetBuffer() );
To print the value of rtl::OUString directly in the debugger, you can use
dbg_dump()
.
It is intended to be called interactively from the debugger, in both
debug and non-debug builds of OOo. You can see the definition in
sal/rtl/source/debugprint.cxx.
Some code snippets about manipulating those objects can be found on the codesnippets service page :
[1]
Linkoo & Limitations
Linkoo is the tool that implements the
-l
functionality of
bin/ooinstall. It essentially
sym-links files of similar names into your local tree,
allowing a fast development iteration.
It is however slightly limited - some of the modules
cannot be linked for various reasons; these are:
cppuhelper
and
configmgr
,
thus in the rare case that these are altered, they
must be copied manually into
/opt/OOInstall/program
.
In addition symlinks cannot be used for soffice.bin, and this is more commonly altered - it has to be installed from
desktop/unxlngi4.pro/bin/soffice
NB. with an appended '.bin'
Read the Fine manual
With the power of C++ comes the ability to shoot yourself in the foot all the more easily; (and implicitly), cf.
Holub, Rules for C and C++ programming, McGraw-Hill, 95.
The best way to prepare yourself for battle is to read the
OpenOffice coding guidelines, and for the easily confused c'tor / d'tor is short for
constructor / destructor.
Also, there's an extensive list of
recommended literature about C++ - but that's of course
no prerequisite to start coding.
Sending patches
The toplevel structure of the OO.o source code is not the same as the
layout of the CVS repository [ a good rational for this strange state
of affairs is absent ]. Thus to work out what real module a file is in
you need to do eg.
cd binfilter
cat CVS/Repository
framework/binfilter
This shows you that the '
binfilter' directory is part of the
'framework' project.
These days there is a
hackers bug filing page that will assign bugs to the correct project, and the correct owner to get rapid attention.
Starting the right app
As you start soffice.bin, there are several useful parameters to
use to accelerate your debugging experience; particularly
-writer
,
-calc
,
-draw
,
and (the wizardly painful)
-impress
arguments.
Understanding D' make (man)
While the build system is in similar to many other systems, it is
also perhaps slightly different. The overview is that each module is
built, and then the results are
delivered into the
solver. Each module builds against the headers in the solver. Thus there are a few intricacies.
-
build — this perl script solenv/bin/build.pl is
used in conjunction with prj/build.lst
to ensure that every module that is needed is built first.
build then un-winds internal module dependencies, and builds
each module with a chdir, dmake pair.
-
deliver — this perl script solenv/bin/deliver.pl
installs headers, and libraries (etc.) into the solver, as
informed by prj/d.lst. Crucially
deliver ensures that the date stamp on any file that is
installed to the solver is the same as that in the module's
directory. This ensures, that (particularly for headers) that
there is no dependency cascade triggering re-builds in other
modules.
Standard directories
There are various standard directories and files in most of the modules that make up OO.o, here are some of the more useful:
- prj
- build.lst — this lists directories to be made, '^#' comments are allowed, the order of the list is immaterial see detail, it is dictates build's operation.
- d.lst — this file describes the deliver process, see detail.
- util — typically the util directory is charged with
glueing together the sub-libraries for each sub-module into a single
large library, adding system library dependencies, building GUI resource
files etc. All the work is described in makefile.mk, this is usually the last directory to be built in a project.
- inc — public headers are typically separated into an
'inc' directory, these will be installed into the solver by the
'deliver' phase (using prj/d.lst)
Build's mode of operation is to invoke 'dmake' in each of the
projects' directories with a given dependency order. dmake then executes
the rules in makefile.mk.
prj/build.lst
On first view build.lst looks scary:
vc vcl : NAS:nas FREETYPE:freetype psprint rsc sot ucbhelper unotools sysui NULL
vc vcl usr1 - all vc_mkout NULL
vc vcl\source\unotypes nmake - all vc_unot NULL
vc vcl\source\glyphs nmake - all vc_glyphs vc_unot NULL
...
vc vcl\mac\source\src nmake - m vc__srcm vc_unot NULL
vc vcl\util nmake - all
vc_util vc__plug.u vc__appa.u vc__appm.m vc__appu.u vc__appw.w vc__gdim.m
vc__gdiu.u vc__gdiw.w vc__srcm.m vc__srcu.u vc__srcw.w
vc__wina.u vc__winm.m vc__winu.u vc__winw.w vc__du.u
vc__gtka.u vc__gtkw.u vc__gtkg.u vc__kde.u vc_app
vc_ctrl vc_gdi vc_hlp vc_src vc_win vc_glyphs NULL
so we need to try and un-pack what's going on here, which is in fact
not
as odd as it might seem at first glance. Firstly lists are terminated
by the 'NULL' string. Every line is prefixed by a shortcut which has to
be unique, no two modules are allowed to have the same shortcut.
So we see in the vcl case that
vcl\source\unotypes (vc_unot) has to be built before
vcl\source\glyphs (vc_glyphs). For Mac
vcl\mac\source\src (vc__srcm) has to be built before
vcl\util (vc_util) It is
important
to understand that the order of the list is ~immaterial, and instead of
a simple ordered list, we have a more complex internal dependency
system — this contrasts with most other make systems.