Thread overview
Linking external functions?
Apr 18, 2023
DLearner
Apr 18, 2023
ag0aep6g
Apr 18, 2023
DLearner
Apr 18, 2023
ag0aep6g
Apr 18, 2023
thinkunix
Apr 18, 2023
DLearner
Apr 19, 2023
thinkunix
April 18, 2023

Wanted to try out linking two source files independantly compiled.

ExtCallee.d source file:

extern(C) void ExtCallee() {
   import std.stdio;

   writeln("Entered: ", __FUNCTION__);
   writeln("Exiting: ", __FUNCTION__);
}

ExtMain.d source file:

void main() {
   import std.stdio;
   extern(C) void ExtCallee();


   writeln("Entered: ", __FUNCTION__);

   ExtCallee();

   writeln("Exiting: ", __FUNCTION__);
}

Then:

dmd ExtCallee -c

which worked, producing .obj file.

However:

dmd ExtCallee.obj -run ExtMain
lld-link: error: undefined symbol: __D7ExtMain4mainFZ9ExtCalleeUZv
>>> referenced by ExtMain.obj:(__Dmain)
Error: linker exited with status 1

Ideas?

April 18, 2023

On Tuesday, 18 April 2023 at 19:49:04 UTC, DLearner wrote:

>
void main() {
   import std.stdio;
   extern(C) void ExtCallee();

Move that declaration out of main.

April 18, 2023

On Tuesday, 18 April 2023 at 20:00:18 UTC, ag0aep6g wrote:

>

On Tuesday, 18 April 2023 at 19:49:04 UTC, DLearner wrote:

>
void main() {
   import std.stdio;
   extern(C) void ExtCallee();

Move that declaration out of main.

Thanks - worked!

Is the declaration inside main not visible to the linker?

April 18, 2023

On Tuesday, 18 April 2023 at 20:05:05 UTC, DLearner wrote:

>

Is the declaration inside main not visible to the linker?

It affects the (fully qualified and mangled) name of the function. Compare:

extern(C) void ExtCallee();
pragma(msg, ExtCallee.mangleof); /* ExtCallee (correct name) */
void main()
{
    extern(C) void ExtCallee();
    pragma(msg, ExtCallee.mangleof); /* _D7ExtMain4mainFZ9ExtCalleeUZv (incorrect) */
}

I don't know the rationale behind that behavior, if there is one. Generally, just put your extern(C) prototypes in module scope.

April 18, 2023
DLearner via Digitalmars-d-learn wrote:
> Wanted to try out linking two source files independantly compiled.
> 
> ExtCallee.d source file:
> ```
> extern(C) void ExtCallee() {
>     import std.stdio;
> 
>     writeln("Entered: ", __FUNCTION__);
>     writeln("Exiting: ", __FUNCTION__);
> }
> ```
> ExtMain.d source file:
> ```
> void main() {
>     import std.stdio;
>     extern(C) void ExtCallee();
> 
> 
>     writeln("Entered: ", __FUNCTION__);
> 
>     ExtCallee();
> 
>     writeln("Exiting: ", __FUNCTION__);
> }


What is the advantage of using extern(C)?
Since both are D source files, why wouldn't you do just this:

```d
// ExtCallee.d
void ExtCallee()
{
        import std.stdio;

        writeln("Entered:  ", __FUNCTION__);
        writeln("Exiting:  ", __FUNCTION__);
}
```

```d
// ExtMain.d
void main()
{
        import std.stdio;
        import ExtCallee;

        writeln("Entered:  ", __FUNCTION__);

	// I had to scope this to get it to compile
        // If instead I put the function in myfn.d and
        // did "import myfn;" it works without the scope operator.
        ExtCallee.ExtCallee();

        writeln("Exiting:  ", __FUNCTION__);
}
```

Compile with:
$ dmd ExtCallee.d ExtMain.d -of=prog


Without extern(C), the linker mangles names:

$ nm ExtCallee.o | grep ExtCallee
0000000000000000 R _D9ExtCallee12__ModuleInfoZ
0000000000000000 W _D9ExtCalleeQkFZv

$ nm ExtMain.o | grep ExtCallee
                 U _D9ExtCalleeQkFZv


With extern(C), the linker does not mangle names:

$ nm ExtCallee.o | grep ExtCallee
0000000000000000 W ExtCallee
0000000000000000 R _D9ExtCallee12__ModuleInfoZ

$ nm ExtMain.o | grep ExtCallee
                 U ExtCallee


If not calling C code, why use extern(C) for D code?
scot
April 18, 2023
On Tuesday, 18 April 2023 at 21:31:21 UTC, thinkunix wrote:
[...]
> If not calling C code, why use extern(C) for D code?
Wanted to test out options of calling D routine (possibly -betterC) from both C and (full) D.


April 18, 2023
DLearner via Digitalmars-d-learn wrote:
> On Tuesday, 18 April 2023 at 21:31:21 UTC, thinkunix wrote:
> [...]
>> If not calling C code, why use extern(C) for D code?
> Wanted to test out options of calling D routine (possibly -betterC) from both C and (full) D.
> 
> 

OK, thanks.