www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - DMD Refuses to Compile Multiple Source Files

reply Samwise <mggmugginsmc gmail.com> writes:
Alright. For the sake of this argument, I'm going to post all the 
stuff about a really tiny boring program that quite literally 
does nothing, even though I found this issue when I was working 
with a much larger project with more functions. Basically I'm 
getting errors when I attempt to compile multiple source files 
using the DMD. It does not matter whether it's through dub or 
just straight DMD. A few little code snippets and DMD output (The 
dub output is basically the same as the DMD, just with a few more 
lines):

hello.d (This file contains the main function, as you can see. I 
put the headers in here to simplify things.):

import std.stdio;

int getReturnCode();

int main() {
	writeln("Hello World!");
	return getReturnCode();
}

getReturnCode.d (This file is the home of my cute function, which 
does nothing...):

int getReturnCode() {
	return 4;
}

Those were the complete contents of my two basic program files. 
The Compilation works fine (Can generate both object files using 
the -c switch with the DMD). However, it just stops when 
linking...

$ dmd getReturnCode.d hello.d
getReturnCode.o: In function `_Dmain':
hello.d:(.text._Dmain+0x17): undefined reference to 
`_D5hello13getReturnCodeFZi'
collect2: error: ld returned 1 exit status
--- errorlevel 1

This basic output is what I'm getting whenever I try to compile a 
main function using a function call that is for a function not 
included in the main.d, regardless of pretty much any other thing.

Thank you for reading and at least attempting to help me solve 
this issue...
~Sam
Jan 17
parent reply James Buren <ryuo bfcloud.me> writes:
Import the source file containing the external function instead 
of writing that prototype. It should compile then.
Jan 17
parent reply Samwise <mggmugginsmc gmail.com> writes:
On Wednesday, 18 January 2017 at 02:48:45 UTC, James Buren wrote:
 Import the source file containing the external function instead 
 of writing that prototype. It should compile then.
This seems like a workaround more than a permanent solution. It would work, but still. I'm also not sure about the syntax for that (Given that getReturnCode.d is in the same directory as hello.d). ~Sam
Jan 17
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Wednesday, 18 January 2017 at 03:11:08 UTC, Samwise wrote:
 On Wednesday, 18 January 2017 at 02:48:45 UTC, James Buren 
 wrote:
 Import the source file containing the external function 
 instead of writing that prototype. It should compile then.
This seems like a workaround more than a permanent solution. It would work, but still. I'm also not sure about the syntax for that (Given that getReturnCode.d is in the same directory as hello.d). ~Sam
In extern (D) functions (which is the default) The module name is part of the mangled name. What you are trying to do would work , if the getReturnType would be extern(C).
Jan 17
parent reply Samwise <mggmugginsmc gmail.com> writes:
On Wednesday, 18 January 2017 at 03:25:47 UTC, Stefan Koch wrote:
 On Wednesday, 18 January 2017 at 03:11:08 UTC, Samwise wrote:
 On Wednesday, 18 January 2017 at 02:48:45 UTC, James Buren 
 wrote:
 Import the source file containing the external function 
 instead of writing that prototype. It should compile then.
This seems like a workaround more than a permanent solution. It would work, but still. I'm also not sure about the syntax for that (Given that getReturnCode.d is in the same directory as hello.d). ~Sam
In extern (D) functions (which is the default) The module name is part of the mangled name. What you are trying to do would work , if the getReturnType would be extern(C).
Without changing anything about the hello.d file from above, and the only change being adding the extern keyword to the getReturnValue.d like this: extern int getReturnCode() { return 4; } still does not compile using the command from above. I may very well be misunderstanding you though. I've not been doing this particularly long... ~Sam
Jan 17
parent reply ketmar <ketmar ketmar.no-ip.org> writes:
On Wednesday, 18 January 2017 at 03:37:46 UTC, Samwise wrote:
 extern int getReturnCode() {
 	return 4;
 }

 still does not compile using the command from above. I may very 
 well be misunderstanding you though.
yep. *both* prototype and real declaration should be `extern(C)`. `(C)` part is important too!
Jan 17
parent reply Samwise <mggmugginsmc gmail.com> writes:
On Wednesday, 18 January 2017 at 03:51:50 UTC, ketmar wrote:
 On Wednesday, 18 January 2017 at 03:37:46 UTC, Samwise wrote:
 extern int getReturnCode() {
 	return 4;
 }

 still does not compile using the command from above. I may 
 very well be misunderstanding you though.
yep. *both* prototype and real declaration should be `extern(C)`. `(C)` part is important too!
I have both the header in hello.d and the actual function in getReturnCode.d as extern, and it still fails with the same error.
Jan 17
next sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
On Wednesday, 18 January 2017 at 04:06:23 UTC, Samwise wrote:
 I have both the header in hello.d and the actual function in 
 getReturnCode.d as extern, and it still fails with the same 
 error.
nope. it works.
Jan 17
prev sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Wednesday, 18 January 2017 at 04:06:23 UTC, Samwise wrote:
 On Wednesday, 18 January 2017 at 03:51:50 UTC, ketmar wrote:
 On Wednesday, 18 January 2017 at 03:37:46 UTC, Samwise wrote:
 extern int getReturnCode() {
 	return 4;
 }

 still does not compile using the command from above. I may 
 very well be misunderstanding you though.
yep. *both* prototype and real declaration should b `extern(C)`. `(C)` part is important too!
I have both the header in hello.d and the actual function in getReturnCode.d as extern, and it still fails with the same error.
extern(C), not simply extern. It turns off the name mangling. But really, the proper thing to do is to drop the prototype and import the module with the implementation. It's tge way modules are intended to be used. Unless you're doing something specidic like writing a library that calls an arbitrary user function.
Jan 17
next sibling parent reply Samwise <mggmugginsmc gmail.com> writes:
On Wednesday, 18 January 2017 at 04:25:42 UTC, Mike Parker wrote:
 extern(C), not simply extern. It turns off the name mangling. 
 But really, the proper thing to do is to drop the prototype and 
 import the module with the implementation. It's tge way modules 
 are intended to be used. Unless you're doing something specidic 
 like writing a library that calls an arbitrary user function.
Alright, so I misunderstood what ketmar was saying. His solution did work. I'm just not sure I understand what you are trying to say here:
 But really, the proper thing to do is to drop the prototype and 
 import the module with the implementation.
This will still preserve my multiple source files, without worrying about the headers, right? Thanks, ~Sam
Jan 18
next sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Wednesday, 18 January 2017 at 19:28:20 UTC, Samwise wrote:
 On Wednesday, 18 January 2017 at 04:25:42 UTC, Mike Parker 
 wrote:
 extern(C), not simply extern. It turns off the name mangling. 
 But really, the proper thing to do is to drop the prototype 
 and import the module with the implementation. It's tge way 
 modules are intended to be used. Unless you're doing something 
 specidic like writing a library that calls an arbitrary user 
 function.
Alright, so I misunderstood what ketmar was saying. His solution did work. I'm just not sure I understand what you are trying to say here:
 But really, the proper thing to do is to drop the prototype 
 and import the module with the implementation.
This will still preserve my multiple source files, without worrying about the headers, right? Thanks, ~Sam
Yes. Take a look at some random projects from code.dlang.org and look at the way they have laid out their modules and what they import and from where.
Jan 18
parent Samwise <mggmugginsmc gmail.com> writes:
Thanks loads. I got it working using those modules.
~Sam
Jan 18
prev sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Wednesday, 18 January 2017 at 19:28:20 UTC, Samwise wrote:

 Alright, so I misunderstood what ketmar was saying. His 
 solution did work. I'm just not sure I understand what you are 
 trying to say here:

 But really, the proper thing to do is to drop the prototype 
 and import the module with the implementation.
This will still preserve my multiple source files, without worrying about the headers, right? Thanks, ~Sam
First, let's get some terminology straightened out. This: int getReturnCode(); is not a "header". It's a function declaration (or function prototype). Both C and C++ are sensitive to the location of declarations and implementations, i.e. you can't call a function or use a type unless it has been declared or implemented before the point at which it is called: ``` // Error! funcA is used before it is declared void funcB() { funcA(); } void funcA() { ... } ``` The example can be fixed by either moving the implementation of funcA above the implementation of funkB, or adding a prototype of funcA above funkB: ``` void funcA(); void funcB() { funcA(); } void funcA() { ... } ``` In C and C++, a "header" is a file that is used to collect publicly usable type and function declarations in one place. This saves the work of declaring them in every source file that needs them. D was designed with a module system to avoid the need for function prototypes and header files. You can still use them, as they are handy when interfacing with C and C++ programs, but they are not required. D is also not sensitive to the location of type and function implementations. The first example above would not be an error in D. You can implement a function before or after its point of use. So the D way is to forego the use of function prototypes entirely. You implement your functions and types in modules (source files), then use the import statement to make the declarations in other modules. So your initial example becomes: ``` // main.d import std.stdio; import returncode; int main() { writeln("Hello World!"); return getReturnCode(); } // returncode.d module returncode; int getReturnCode() { return 4; } ```
Jan 18
parent Mike Parker <aldacron gmail.com> writes:
On Wednesday, 18 January 2017 at 23:12:15 UTC, Mike Parker wrote:

 (source files), then use the import statement to make the 
 declarations in other modules.
Sorry, this should read "make the implementations available to other modules".
Jan 18
prev sibling parent Samwise <mggmugginsmc gmail.com> writes:
On Wednesday, 18 January 2017 at 04:25:42 UTC, Mike Parker wrote:
 extern(C), not simply extern. It turns off the name mangling. 
 But really, the proper thing to do is to drop the prototype and 
 import the module with the implementation. It's tge way modules 
 are intended to be used. Unless you're doing something specidic 
 like writing a library that calls an arbitrary user function.
Alright, so I misunderstood what ketmar was saying. His solution did work. I'm just not sure I understand what you are trying to say here: I've started using dub for things, and I've learned a lot since this thread. Anyway, thanks for the support with this everybody.
Mar 07