3

I have a small program which I want to execute via the command line. I run it from inside the IDE and it runs fine. I copy the entire compilation command and paste it on the MSVS command prompt and I get unresolved symbol linker errors (I have done this before on some programs that didn't require passing of linker options).

I've read from the documentation that I need to specify /link linker-options (from here). But when I do so, I get other errors. Then as instructed I went here, which should say how I should specify the linker options. But it doesn't, it's just a reference of those for link.exe. Do I need to pipe the cl command to link.exe, do I need to execute it after cl? I cannot find an example either.

Just for testing, the simple program main.cpp is the following:

#include <iostream>
#include <Windows.h>
#include <string>

int main()
{
    DWORD pid;
    HWND hwnd = FindWindow(0, L"Calculator");
    GetWindowThreadProcessId(hwnd, &pid);
    if (hwnd) {
        std::cout << "Window is open, id = " << pid;
    }
    else {
        std::cout << "Window not found" << '\n';
    }
    system("Pause");
}

It works properly inside the IDE. Now, as I mentioned, I copy the complete commands from MSVS 2017 compiler section:/JMC /permissive- /we"4239" /GS /Zc:rvalueCast /W3 /Zc:wchar_t /ZI /Gm- /Od /Fd"x64\Debug\vc141.pdb" /Zc:inline /fp:precise /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /std:c++17 /FC /Fa"x64\Debug\" /EHsc /nologo /Fo"x64\Debug\" /Fp"x64\Debug\GetProcessByName.pch" /diagnostics:classic

and linker part: /OUT:"J:\nik\Documents\Visual_Studio_Projects\GetProcess\x64\Debug\GetProcessByName.exe" /MANIFEST /NXCOMPAT /PDB:"J:\nik\Documents\Visual_Studio_Projects\GetProcess\x64\Debug\GetProcessByName.pdb" /DYNAMICBASE "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /DEBUG /MACHINE:X64 /INCREMENTAL /PGD:"J:\nik\Documents\Visual_Studio_Projects\GetProcess\x64\Debug\GetProcessByName.pgd" /SUBSYSTEM:CONSOLE /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"x64\Debug\GetProcessByName.exe.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /TLBID:1

and as Mike said, I combine them as follows cl [compile-options] main.cpp /link [linker-options] and execute this command from the directory where main.cpp is located.

The output is: c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.1 5.26726\include\xlocale(319): warning C4530: C++ exception handler used, but unw ind semantics are not enabled. Specify /EHsc C:\Users\nik\documents\Visual_Studio_Projects\GetProcess\GetProcessByName\m ain.cpp : fatal error C1083: Cannot open compiler generated file: 'x64\Debug" /E Hsc /nologo /Fox64\Debug".asm': Invalid argument

How do I properly "pass"/specify linker options to build the program from the command line and run it?

KeyC0de
  • 4,728
  • 8
  • 44
  • 68
  • `cl [compile-options] /link [linker-options]` is quite all right. So is `cl [compile-options]` followed by `link [linker-options]`. You are evidently getting `[linker-options]` wrong but to get help with that you need to edit your post to show us the failing commandline and the errors that follow from it, verbatim. – Mike Kinghan Oct 10 '18 at 08:18
  • @MikeKinghan Thanks for the help. I have updated the question. – KeyC0de Oct 10 '18 at 18:10

1 Answers1

2

The error you are seeing is a shell parse error in the compilation options. So the command does not get as far as actually compiling, let alone linking, and if there are in fact going to be any problems arising from your linkage options, the question doesn't show us what they are.

The parse error we see is caused by the option:

/Fa"x64\Debug\"

The documentation of /Fa stipulates that when the form:

/Fa directory\

is used, to specify an output directory for assembly listings, the trailing \ must be present to distinguish this form of the option from:

/Fa filename

You have done that, and placed the directory name in quotes - "x64\Debug\".

When the Windows shell (cmd) with which you are executing your command parses a commandline it treats \ within quotation "..." as an escape character.

Thus the trailing \ escapes the closing " of "x64\Debug\" and the directory\ parameter of /Fa is continued through subsequent options of the command until finally the compiler identifies the form:

/Fa filename

and attempts, unsuccessfully, to open an assembly listing called:

'x64\Debug" /E Hsc /nologo /Fox64\Debug".asm'

You can avoid this parse error in any of the following ways:

Escape the backslashes in the quoted pathnames

Change:

/Fa"x64\Debug\"

to:

/Fa"x64\\Debug\\"

and similarly for other pathnames in your commandline options.

Remove the quotation marks

Change:

/Fa"x64\Debug\"

to:

/Fax64\Debug\

Quotations around pathnames are needed only if there are embedded spaces in the pathnames, so that the shell will parse a single string instead of two or more. You haven't got any embedded spaces in any of the pathnames in any of your commandline options, so you could remove the quotes from all of them.

Use / instead of \ as the pathname separator

Change:

/Fa"x64\Debug\"

to:

/Fa"x64/Debug/"

and similarly for other pathnames in your commandline. Windows is the only operating system to use \ as a pathname separator. Others use /, and Windows has accepted both in recent versions.

If this results in any visual confusion between / used as a path separator ("x64/Debug/") and / used as an option-prefix (/Fa), cl will also allow you to use unix-style options, e.g. -Fa instead of /Fa.

And of course you could also remove the quotation marks and use / as the path separator.

If you use one of these solutions only to fix the parse error in:

/Fa"x64\Debug\"

then the same parse error will be provoked by the subsequent option:

/Fo"x64\Debug\"

So apply the chosen solution consistently to the whole commandline.

Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182