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