Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28438 Discussions

Calling Subroutines on separated files on multiples directories (Linux x Windows)

j-miguel
Beginner
1,411 Views

Hey there,

We have a quite large Fortran program that's developed and builded using Visual Studio and Ifort for windows. On the linux side, we used to get the .dep generated on windows side, proccess it using a script, and create a command line call with the files on the order needed for the compilation. Now, I'm trying to rewrite the linux build using CMake.

After many solved problems (casing, enconding, ...) I've encountered some errors on the linking part. We have some subroutines defined on separated files that get called straight from other files like: 

CALL SUBROUTINE_NAME ()

I guess VisualStudio is somehow handling this linking but when I try to compile it using CMake on linux i get an error "undefined reference to SUBROUTINE_NAME". My first tought was trying to include the file where this routine is defined but the subroutines are defined on multiple directories and, as far I understand, unless I put all this places on the include path for the compiler they can't be found.

Another option would be rewriting all this as modules and using them where needed. I guess this would be a cleaner solution but also a lot of work that I'm not sure I'd have the time for now.

 

First of all, I'd like to make sure my reasoning seems right and then what would be the best or some alternatives way to deal with this,  like a way to manually include the paths for each occurrence or if there's a way to make CMake work like VisualStudio and resolve this references for example.

 

Thanks in advance for any insight and don't hesitate to get in touch and ask for more information if needed.

 

 

0 Kudos
14 Replies
j-miguel
Beginner
1,404 Views

Despite using the Ifort compiler, after posting I realized that this is actually more about CMake and Fortran than a problem with the compiler. Sorry for any trouble and feel free to delete this if you feel that's better.

But, as I'm sure you all have a lot of experience around here, I hope to get some insights anyway.

0 Kudos
mecej4
Honored Contributor III
1,398 Views

Two situations come to mind in which "undefined external" references may be encountered. The first situation concerns compiling one of several source files but forgetting to specify the -c compiler option. The second situation is related to linking a number of .o files but leaving out one or more required object or library files from the link command line. See if either of these describes your case.

0 Kudos
j-miguel
Beginner
1,376 Views

Thanks for your answer @mecej4 , as I'm using CMake (and passing all .for files recursively) the .o for the subroutine is indeed been generated. In this case, assuming the .o is corretly been passed to the compiler, a simply CALL statement for the SUBROUTINE (without include) should be enough?

Another question, if I explicitly include the subroutine file, the .o would still be generated or would it be "bundled" with the main file .o where it was included?

0 Kudos
mecej4
Honored Contributor III
1,331 Views

In effect, you may think of INCLUDE statements as being processed before any compilation is performed. Note, as well, that any text can be INCLUDEd; for example, comment lines.

Fortran compilers on Linux and Windows produce one object file per source file (and, depending on what the source file contains, some module files; these module files are not used in the linking process). The source file may contain one or more program units, and may contain zero or more INCLUDE statements. The presence of INCLUDE statements has no effect on the number of object files produced.

I have to confess that I find your questions so ambiguously worded that I do not really understand the questions.

0 Kudos
j-miguel
Beginner
1,296 Views

Sorry for any confusion caused @mecej4 , I could blame it on not been a native speaker but I guess it's probably more "end of the day and should already be sleeping" problem. Anyway, thanks for your reply you at least already helped me to rule out some doubts about the include.

Just to give more context, I'm clearly not used to Fortran (I started with C but now mainly code in C#), I can understand and code bit but especially the compiling part using CMake is somewhat new to me.

Let me try to rephrase and break down my questions:

 

1) When I want to call a subroutine that's defined on another file, do I always need to include this file?

2) Or if I already have the .o compiled, and correctly been passed on the command line to the compiler I could directly call it from my main file? (with out including it or referencing it someway)

 

 

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,188 Views

>>Fortran compilers on Linux and Windows produce one object file per source file. 

unless the source file contains module(s) with/without non-contained procedures. 

I agree that it is likely that the CMake script did not include the necessary .o file and this may be caused the .o file not being generated, or generated in the wrong place and/or you not specifying the dependencies correctly in your makefile.

 

Jim Dempsey

0 Kudos
j-miguel
Beginner
1,164 Views

I've reached the same conclusion @jimdempseyatthecove, I've managed to manually compile the file passing the .o of the separated subroutine but couldn't get CMake to include it as needed.

 

Whenever I use a module, CMake can automatically add the module as a dependency for the file. But on this cases, where I'm calling the subroutine directly it doesn't generate the correct dependency for the Makefile.

For CMake, I'm passing all .for files like:

file(GLOB_RECURSE sources ./src/*.for)

Therefore, the separated subroutine does get compiled into a .o object but it is not been added correctly as dependency on the Makefile.

 

This is clearly not compiler related, but if you have some suggestions, any help would be of great value.

0 Kudos
andrew_4619
Honored Contributor II
1,158 Views

I don't have much knowledge on Cmake but I read this which may help>>>>>>>

You can't change the output directory of object/intermediate files in CMake. That's by design (to allow several identical output names in one project):

"There is no way to change that name. CMake creates an exact copy of the source tree in the binary tree."

But with version 3.9 CMake learned to export object libraries:

cmake_minimum_required(VERSION 3.9)

project(CorePorject)

file(WRITE "core.cpp" "")
file(WRITE "helper.cpp" "")
set(sourcefiles "core.cpp" "helper.cpp")

add_library(core OBJECT ${sourcefiles})    

export(
    TARGETS core
    FILE core.cmake 
    NAMESPACE Core_
)

 

0 Kudos
j-miguel
Beginner
1,141 Views

Thanks @andrew_4619 , yes, I suppose this would work. But to implement something like this, if I understand it correctly, I'd need to manually get the path for each subroutine been imported through out the project to add them as a library, right?

If I follow this route, perhaps it would be better to move all of this subroutines to a separated location. I'm sure this would be a better solution, but if I get into refactoring I guess rewriting this routines as module/s would be better anyway.

Ideally, I'd like to CMake to resolve the dependencies generated by the call statements as it does for the modules.

0 Kudos
andrew_4619
Honored Contributor II
1,136 Views

Maybe you can do it with wildcards like you did to select the source files? Or maybe you can use a wildcard to list all the source files and cut/paste it into cmake?

0 Kudos
j-miguel
Beginner
1,119 Views

The problem is that those subroutines files are scattered through out the project, but I guess you're right, I'd need to somehow at least identify those files.

0 Kudos
mecej4
Honored Contributor III
1,232 Views

When your source code, whether in C, Fortran or any compiled language, contains calls to external routines (subroutines, functions, etc.), compiling the source code produces a .o file that contains a list of "external symbols". When you link a number of .o files and libraries, those external symbols need to be present in one of the .o files or libraries.

There is never a need to include one source file in another just for the purpose of being able to call external routines. Think about the SQRT function. When you write x = sqrt(y), where is the sqrt function defined? Did you ever write source code for the SQRT function? The EXP function? In C, in a source file that uses the sqrt() function, you may have inserted an "include <math.h>" directive. What was the purpose of doing so?

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,158 Views

Perhaps it would help if you show your makefile.

Jim Dempsey

0 Kudos
j-miguel
Beginner
1,135 Views

@jimdempseyatthecove  the Makefile been generated by CMake is 15000+ lines long, I'm not sure this would be of great help.

 

Here is my CMakeLists.txt logic:

 

file(GLOB_RECURSE sources ./src/*.for)
add_executable(program_name ${sources}

target_include_directories(program_name PUBLIC "./src/includes")

 

 

Unless I refactor the code for separating this subroutines or even turning them into modules, I guess my real problem is making CMake follow those dependencies generated by those call statements as it does for the modules.

0 Kudos
Reply