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

Linking problems when changing from WinMain() to main()

jgruendler
Beginner
2,254 Views

I have a large, old, mixed-language program that I've been "porting" from the Watcom C and FORTRAN compilers to the MS C and Intel Fortran compilers. In addition, I'm trying to get rid of some stray Windows-specific code that's gotten in over the years, and therein lies my current problem:

At present, the program uses WinMain() as its startup routine, which uses the Windows function GetCommandLine() to build argc and argv, and then calls a function called int "ciexec(int argc, char *argv[])", which had been main() before the program was ported to Windows. However, this causes functions using stdio, e.g. printf(), not to work. So, I tried commenting out the WinMain() stuff and renaming ciexec() back to main(), but then I get this error:

libifcoremt.lib(for_main.obj) : error LNK2019: unresolved external symbol MAIN__
referenced in function main

So, I tried renaming main() to MAIN__(), which allows the program to link, but then I get a run-time error because argc appears to contain a memory address instead of the number of argument and argv is NULL.

I'm completely at a loss about how to:

  1. get the program to link with the main function named "main()" instead of "MAIN__()", and
  2. have argc and argv be correct.

Thank you in advance for your help!

0 Kudos
7 Replies
Steven_L_Intel1
Employee
2,254 Views
Fortran is not C. If you want a main program it has to be a PROGRAM or not have a SUBROUTINE, FUNCTION, BLOCK DATA or MODULE first line. For Fortran programs, the actual "main" entry point is in the run-time library.

My advice is to create a new project as a "console application" and add your code to that. Rewrite the WinMain routine to be a main program unit. Note that making this change also involves linker setting changes so just changing the code is not enough.

Have you considered using the Fortran 2003 intrinsics for getting arguments from the command line?
0 Kudos
jgruendler
Beginner
2,254 Views
MADsblionel:
Fortran is not C. If you want a main program it has to be a PROGRAM or not have a SUBROUTINE, FUNCTION, BLOCK DATA or MODULE first line.

Yes, I'm well aware of that. I don't want a Fortran main program; I want to switch from this:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
int argc;
char **argv;
/* BuildArgVector() uses the Win32 function GetCommandLine() to populate argc and argv */
BuildArgVector(&argc, &argv);
ciexec(argc, argv);
}

int ciexec(int argc, char **argv) {
/* Fortran gets called inside here */
}

to this:

int main(int argc, char **argv) {
/* Fortran gets called inside here */
}

In other words, I just want it to correctly use the C main function that I already have, without a stupid Win32 wrapper around it!

MADsblionel:
For Fortran programs, the actual "main" entry point is in the run-time library.

Yes, I kinda figured from the "(for_main.obj)" bit in the error message that something related to that was going on. But how do I fix (i.e., get rid of) it?

MADsblionel:
My advice is to create a new project as a "console application" and add your code to that. Rewrite the WinMain routine to be a main program unit. Note that making this change also involves linker setting changes so just changing the code is not enough.

I neglected to mention that I'm compiling from the command-line. I am doing for several reasons:

  • When I say "mixed-language," I don't mean just C and Fortran. I mean C, Fortran, and two in-house languages that get precompiled into C and Fortran respectively. That sort of thing doesn't work very well in Visual Studio unless I wrote some kind of extensions, which I have neither the time nor skill to do at the moment.
  • There was already an established build system using shell scripts, so I just modified those to call the Intel and MS compilers instead of the Watcom ones.
  • I tried to set up a Visual Studio solution (with separate projects per language, as the documentation says), but could never get it to work.
  • I don't like the stupid Microsoft GUI-based build system anyway. It's too [censored] hard to figure out what all the [censored] settings are, and it doesn't tell you what it's [censored] doing!

I'll try again to make a Visual Studio project if you want, but I'd really much rather have advice about building from the command line. Speaking of which, here are my current scripts for building C files, building Fortran files, aggregating into a library, and linking:

"C:Program Files (x86)Microsoft Visual Studio 8VCinamd64cl.exe" -Zi -nologo -w -I"c:gtices ewinc" -DDOS -D_WINDOWS -DNT -c %1 %2 %3 %4 %5 %6 %7 %8 %9

"C:Program Files (x86)IntelCompilerFortran10.1.011em64tinifort" -Zi -nologo -c %1

< br>for %%a in ( *.obj ) do xilib -nologo -out:"path omylib.lib" "path omylib.lib" %%a


"C:Program Files (x86)Microsoft Visual Studio 8VCinlink.exe" -debug -defaultlib:user32 -defaultlib:advapi32 -out:test.exe *.obj path omylib.lib

I should mention that I'm not some experienced Windows programmer; I'm actually just a student. In fact, I don't even like Windows! I got hired to make this program work in 64-bit mode (porting to Intel/MS compilers is a side-effect of that) because the problem sizes it's being used to solve are getting too big to fit in 4GB of memory. This program has a lot of code, most of which was written before I was born. I haven't even seen the vast majority of it; I'm just dealing with the "Basic System" at the moment, which does things like interpret commands, provide dynamic allocation for old-style Fortran (that may or may not even conform to the '77 standard), etc. The simpler I can make things for myself, the better.

MADsblionel:
Have you considered using the Fortran 2003 intrinsics for getting arguments from the command line?

No, and I would very much prefer not to!

0 Kudos
TimP
Honored Contributor III
2,254 Views
I share your preference for command line. Besides, it's all we have so far for VS2008. (No longer; 10.1.019 supports VS2008 fully). On linux, you might have needed the nofor-main option; shouldn't be the case on Windows.
ifort -help gives the basic story.
0 Kudos
Steven_L_Intel1
Employee
2,254 Views
Oh, I see. Tim's suggestion of -nofor_main is not applicable on Windows - that's for Linux and Mac only.

How are you linking the code? There's a C-calls-Fortran sample provided in version 10 and later under SamplesMixedLanguage. There's a build.bat which builds it from the command line. Compare that to what you're doing and see what the difference is. I think you'll need to specify the link option /subsystem to be console instead of windows.
0 Kudos
jgruendler
Beginner
2,254 Views
MADsblionel:
Oh, I see. Tim's suggestion of -nofor_main is not applicable on Windows - that's for Linux and Mac only.

How are you linking the code? There's a C-calls-Fortran sample provided in version 10 and later under SamplesMixedLanguage. There's a build.bat which builds it from the command line. Compare that to what you're doing and see what the difference is. I think you'll need to specify the link option /subsystem to be console instead of windows.

Modifying my link script to include that as follows:

"C:Program Files (x86)Microsoft Visual Studio 8VCinlink.exe" -debug -subsystem:console -defaultlib:user32 -defaultlib:advapi32 -out:test.exe *.obj path omylib.lib

Makes no difference whatsoever (as I suspected it wouldn't, because the documentation says that setting is the default anyway), and the C=calls-Fortran build script doesn't do anything special.

0 Kudos
Steven_L_Intel1
Employee
2,254 Views
Do you have a Fortran main program somewhere in the code? Can you create a small test case that demonstrates the problem? Offhand I can't think of how you'd get this link error. What's the difference between your program and the example?
0 Kudos
jgruendler
Beginner
2,254 Views

Okay, so I double-checked that there was no Fortran main, and there wasn't. But at the same time, I did notice this bit of code in a header file: #define main ciexec

Well, guess what: that's why it was telling me that main was undefined when I tried to name it normally, as int main(int argc, char **argv), and had to call it MAIN__ instead! And -- I'm guessing here -- by calling it MAIN__, something thought it was a Fortran routine and screwed up the calling convention for it.

In other words, getting rid of that stupid #define statement fixed my problem. : ) Thanks for your help (since, even though you didn't provide the answer yourself, your suggestion led me to it)!

0 Kudos
Reply