Using tango or other static lib in static lib
Mike Parker via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Sat Mar 12 17:06:33 PST 2016
On Saturday, 12 March 2016 at 22:34:19 UTC, Voitech wrote:
> At beginning I want to say that I'm Java devloper so most of
> linking, joining, dependent classes, libs could be solve with
> simple 3 click in eclipse so please be patient with me :).
> I'm using Mono-D under Ubuntu 14.04 to create my project it
> would be a library for further development process, but I'm a
> guy who don't want to invite wheel again and again, so i wanted
> to use Tango-D2 (for now HashMap implemenetation).
Anything wrong with the built in associative arrays that cause
you not to use them?
> From what i red you cant import one static library with another
> but somehow import o. files, or just copy sources .d to proper
> folder and use them as yours (with proper license of course).
> Tango-D2 by itself compiles nicely with bob and produces many
> .o files. How to use them though ?
Forget the word 'import' for a minute. There are two basic steps
to concern yourself with: compiling and linking. D's approach is
the traditional C approach. We can loosely define the terms like
so:
compile: take source files as input and generate object files as
output
link: take object files as input and generate executables (or
shared libraries, but let's not confuse things) as output.
In order to compile, the compiler needs to be aware of every
symbol that is visible and usable in the source module it is
currently compiling. As an example, consider the following two
files:
main.d something.d
When compiling main.d, all of the symbols inside main.d are
visible by default. In order for main.d to use the symbols in
something.d, it must 'import' something.d.
import something;
void main() { aFunctionInSomething(); }
Assuming the implementation of aFunctionInSomething lives in
something.d, it is now visible inside main.d because of the
import. Take away the import, and you get a /compiler error/. The
compiler doesn't know about that function, so you can't use it.
Assuming both files live in the same directory, they can be
compiled with this command:
Once the object files are generated, they are passed to the
linker. The important thing to understand here is that the
'import' statement in the source code above has absolutely no
bearing on the link stage. It is exclusively for the compiler.
The linker will never, ever, see it. All the linker cares about
are symbols in the object files. To fully appreciate that, try
this experiment.
Take the main.d source as it is above. Then implement something.d
like so:
module something;
import std.stdio;
void aFunctionInSomething() { writeln("Something"); }
Next, cd to the directory where you saved the files and compile
them both:
dmd -c main.d
dmd -c something.d
The -c option tells the compiler to only generate the object
files and do not pass them to the linker. The result is that you
will now have two object files. If you next take the following
step (assuming Windows -- change .obj to .o elsehwere):
dmd main.obj something.obj
The compiler will recognize you've passed it object files and
will hand them off to the linker. However, try this:
dmd main.obj
Using the default linker on Windows (OPTLINK -- passing
-m32mscoff or -m64 uses the Microsoft linker if you have it
installed, but the source must be compiled with the same flag)
yields the following output:
OPTLINK (R) for Win32 Release 8.00.17
Copyright (C) Digital Mars 1989-2013 All rights reserved.
http://www.digitalmars.com/ctg/optlink.html
main.obj(main)
Error 42: Symbol Undefined _D9something20aFunctionInSomethingFZv
main.obj(main)
Error 42: Symbol Undefined _D9something12__ModuleInfoZ
--- errorlevel 2
These are linker errors. You can know this because of two things:
the big OPTLINK in the first line and the error type 'Symbol
Undefined'. The Microsoft linker produces this:
main.obj : error LNK2001: unresolved external symbol
_D9something12__ModuleInfoZ
main.obj : error LNK2019: unresolved external symbol
_D9something20aFunctionInSomethingFZv referenced in function
_Dmain
main.exe : fatal error LNK1120: 2 unresolved externals
You can know these are linker errors because of the Microsoft
erro codes containing the 'LNK' prefix and because of 'unresolved
external symbol', which is the equivalent of OPTLINK's 'Symbol
Undefined'. It's important to be able to distinguish linker
errors from compiler errors.
When you pass both objects on the command line, the linker is
then able to find the symbol it needs.
A static library is one or more object files bundled into a
single file:
dmd lib something.d
This will create a static library called something.lib. Then you
can do this:
dmd main.d something.lib
In this particular case, it's exactly equivalent to the following:
dmd -c something.d
dmd main.d something.obj
The benefit of static libraries is when you have multiple object
files:
dmd lib foo.d bar.d baz.d
dmd main.d foo.lib
Much more convenient to deal with one library than three object
files.
> If using sources by just copping them into one folder, creating
> Mono-D project, dmd complains about many, many errors, mostly
> import errors (in tango.sys.win32). I fixed them adding version
> to each of included files and adding some imports first:
> module tango.sys.win32....
> version(Windows){
> ...
> ...
> }
>
> But i think I'm doing something wrong, if Tango-D2 compiles
> with bob it should also by creating project in Mono-D (or this
> is linking problem ?). In Mono-D there is also possibility in
> Project-> Options-> Build-> Compiling to add Libraries (there
> is a tick Link static libraries from nested dependencies) how
> to use this ? Or rather how should i obtain what i want ?
To use a library, you need two things, the source files (or D
interface files, which contain all of the type and function
names, but with most of the code stripped out) and the library
file. If the library file does not exist, you have to compile it
first. Most libraries ship with a build script of some sort -- a
makefile, a DUB configuration, and so on. I haven't used Tango
since the D1 days, but I see that Tango-D2 has a dub.json. So you
should be able to do this:
Assume 'tangoroot' refers to the directory into which you've
pulled the tango source from github.
cd tangoroot
dub -brelease
This will build a release version of the library. Next, you'll
need to tell the compiler where to find both the source files
(for resolving imports during the compilation stage) and the
library (so that it can tell the linker where to find the static
library). Looking at the Tango-D2 setup, I see the source files
are all intended to be imported directly from the root directory
and dub.json is configured to output the library in the same
directory.
You can tell the compiler where the source files are on the
command line with the -I switch. How you tell it where the
library files are is a different story. It depends entirely on
the linker you're using. On Windows, it's easier just to feed the
compiler the full library path. Assuming tangoroot is
C:\dev\tango:
dmd -IC:\dev\tango main.d C:\dev\tango\tango.lib
That should do it. On other systems, you would have to do it like
this (for simplicity, let's assume tango is in ../libs/tango,
relative to the project directory):
dmd -I../libs/tango -L-L../libs/tango main.d -L-ltango
Here, in -L-L, the first -L tells dmd the next flag is a linker
flag and should be passed to the linker. The second -L is the
linker flag telling the system linker a directory in which to
look for libraries. In -L-l, the -L again tells dmd the next flag
is a linker flag. The -l (lowercase L) tells the linker the name
of a library to link with. IIRC, you may be able to do the
following, too:
dmd -I../libs/tango main.d -L-l../libs/tango/libtango.a
When using an IDE like Mono-D, all of this must be configured in
the project settings. You've already discovered where to tell it
which libraries to link with. I've never used Mono-D, so I don't
know if it allows you to specify the full path to a library or if
it requires you to also configure a library directory separately.
At any rate, you need to configure it to know which libraries to
link with, where to find them, and where to find the imported
files.
More information about the Digitalmars-d-learn
mailing list