Home > Software design >  Compile C Programs from Windows Powershell with MSVC
Compile C Programs from Windows Powershell with MSVC

Time:09-24

I know this is a topic that has probably been addressed before, but I can't seem to find a straight answer in the searching I've done, everything is extremely convoluted.

I'm trying to get my Powershell set up so I can compile simple C programs directly from a Powershell terminal, and not need to use Visual Studio or the "developer console" they keep recommending.

So far I have installed the Visual Studio build tools, as I was trying to avoid downloading the entire Visual Studio IDE. I was able to compile a Hello World C program using the developer console as a test to make sure everything was working and it compiled and ran fine. However I want to be able to run cl.exe directly from Powershell without using the developer console.

I managed to add a folder to the environment variables in Windows System properties, and successfully got Powershell to recognize the cl command and show me this:

usage: cl [ option... ] filename... [ /link linkoption... ]

I feel like I'm so close here, but when I actually try to run "cl hello.c" to compile my little test program I get this error:

hello.c(1): fatal error C1034: stdio.h: no include path set

I added the folder "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x64" to the environment variables path section, but I noticed there are multiple cl.exe files in different folders.

Can anyone tell me how to dial this thing in so I can actually have the cl function fully functioning from Powershell? Thanks in advance for any help on this.

P.S. I have WSL installed and have multiple Raspberry Pis that I could use the gcc compiler, but that is not my aim here. I'm also aware of things like MinGW and Cygwin but am not looking to use those solutions. I am trying to get this specific scenario to work: using the cl command in Powershell without the developer console. It can't be THAT hard, and I feel like I'm so close and just need to add a few more Environment variables or something.

Edit: I added ran these commands exactly as written in Powershell and it looked like it worked and didn't give me any errors or anything. I have Version 2019 and updated all the directories as necessary. I noticed none of my directories have "ATLMFC" so I omitted that line. Still getting the same errors unfortunately. Any other ideas or tips would be much appreciated.

set INCLUDE=
"C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC14.29.30133\include";
"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\ucrt";
"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\shared";
"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um";
"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\winrt";
"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\cppwinrt";
set LIB=
"C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.29.30133\lib\x86";
"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\ucrt\x86";
"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\um\x86";
set PATH=
"C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x86";
"C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x86";
"C:\Program Files (x86)\Windows Kits\10\bin\x86";
%PATH%

Here's a screenshot of me trying the cl command in PowerShell and the error it gives. https://imgur.com/a/vI6oYK2

CodePudding user response:

The best answer would be to use the developer prompt that comes with Visual Studio, as it sets all the environemental variables needed by the tools. However, if you insist to do everything by hand, here is what I needed to do.

Opening a command prompt on my windows system and typing cl I get cl is not recognized as an internal or external command. The issue here is that cl.exe is not on my path. I can modify the path environmental variable so that the shell can find cl.exe. On my system this is accomplished by doing

>set PATH="C:\VS2019\VC\Tools\MSVC\14.29.30037\bin\Hostx64\x64";%PATH%

which will add the path to cl to my PATH. Note that this only works on the terminal that I am working in. Once this works, you can set it through the environmental variables so it is persisted and available in all command prompts.

Once, cl is in my path I can attempt to compile the following simple program:

#include <stdio.h>
#include <stdlib.>

int main(int argc, char** argv)
{
    printf("Hello World\n");
    return 0;
}

And I am greeted with C1034: stdio.h no include path set. This means that although the compiler has a built-in set of directories that it looks for include files, it can't find stdio.h. The solution is that I need to tell it where to look.

Now on my system I can find it at "C:\Windows Kits\10\Include\10.0.190410\ucrt". (Paths will be specific to my installation, you will need to find each file on your system).

Now I can tell the compiler where to find that file by using the /I (include search path) option [1]. Executing the following command

cl /I"C:\Windows Kits\10\Include\10.0.19041.0\ucrt hello.c

Gives an error "C1083: Cannot open include file: 'vcruntime.h'. Another search of my hard-drive reveals that file to be at "C:\VS2019\VC\Tools\MSVC\14.29.30037\include", and executing the following command

cl /I"C:\Windows Kits\10\Include\10.0.19041.0\ucrt"/I"C:\VS2019\VC\Tools\MSVC\14.29.30037\include" hello.c

Expanding the above command a bit to just do a compilation we can use the following

cl /c /I"C:\Windows Kits\10\Include\10.0.19041.0\ucrt"/I"C:\VS2019\VC\Tools\MSVC\14.29.30037\include" hello.c /Fo hello.o

To produce the object file hello.o.

Now on to linking. The Microsoft linker is called LINK[2] and starting with

LINK hello.o /OUT:hello.exe

Gives an error "LNK1104: cannot open file 'LIBCMT.lib'. Well this is progress, I gotten through the compilation phase and into the link phase, I only need to tell the compiler where to find the library.

Yet another search of my hard drive shows the library to be at "C:\VS2019\VC\Tools\MSVC\14.29.30037\lib\x64", and running the following command,

LINK hello.o /LIBPATH:"C:\VS2019\VC\Tools\MSVC\14.29.30037\lib\x64" /OUT:hello.exe

Gives the error LNK1104: cannot open file "kernel32.lib", which I found at "C:\Windows Kits\10\lib\10.0.19041.0\um\x64" I also had to add "C:\Windows Kits\10\lib\10.0.19041.0\ucrt\x64", to resolve libucrt.lib". The following command

LINK hello.o /LIBPATH:"C:\VS2019\VC\Tools\MSVC\14.29.30037\lib\x64" /LIBPATH:"C:\Windows Kits\10\lib\10.0.19041.0\um\x64" /LIBPATH:"C:\Windows Kits\10\lib\10.0.19041.0\ucrt\x64" /OUT:hello.exe    

Finally produce the output file hello.exe, which can as expected from a command prompt.

Remember that the above was for a simple hello-world style application. As your program gets bigger, the various paths you will need to specify will get larger as well. You may want to look into using nmake and using makefiles to manage you build.

[1] you can use "cl /?" to see all command line options available with the Microsoft compiler.

[2] you can use "LINK /?" to see all command line options available with the Microsoft linker.

CodePudding user response:

Open up a Visual Studio Developer Command Prompt. Assuming it has defaulted to your %VSINSTALLDIR% as normal, then search for vcvars.bat in that tree.

If you look in that file, you'll see that you need to set INCLUDE, LIB, and PATH to get command-line builds to work.

In particular, the "C" portion of the C/C Runtime is actually in the Windows 10 SDK under:

  • c:\Program Files (x86)\Windows Kits\10\Include\<version>\ucrt for the headers
  • C:\Program Files (x86)\Windows Kits\10\Lib\<version>\ucrt\<arch> for the libraries.

See Microsoft Docs.

Because Visual Studio supports many side-by-side toolsets, the compiler and the VC Runtime and "C " portion of the include/libs are located under: C:\Program Files (x86)\Microsoft Visual Studio\2017\<VSEdition>\VC\Tools\MSVC\<toolset> in the bin, include, and lib/<arch> folders which should be set as part of the environment variables above.

For VS 2017 (15.9) Enterprise edition using the Windows 10 SDK (17763) for example, that would be:

MS-DOS Command Prompt syntax:

set INCLUDE=C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\include;
C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\ucrt;
C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\shared;
C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\um;
C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\winrt;
C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\cppwinrt

The Powershell syntax is:

$env:INCLUDE = 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\include;C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\ucrt;C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\shared;C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\um;C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\winrt;C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\cppwinrt'

Assuming you are creating a 32-bit (x86) program:

MS-DOS Command Prompt:

set LIB=C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\ATLMFC\lib\x86;
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\lib\x86;
C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\ucrt\x86;
C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x86;

PowerShell:

$env:LIB = 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\ATLMFC\lib\x86;C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\lib\x86;C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\ucrt\x86;C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x86;'

This should be sufficient for classic Win32 desktop development. For C /CX, Managed C , and/or UWP development you would need additional directories and the LIBPATH variable set.

And you want the compiler itself to be a 32-bit (x86) EXE:

MS-DOS Command Prompt:

set PATH=C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\bin\HostX86\x86;
C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x86;
C:\Program Files (x86)\Windows Kits\10\bin\x86;
%PATH%

PowerShell:

$env:PATH='C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\bin\HostX86\x86;C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x86;C:\Program Files (x86)\Windows Kits\10\bin\x86;'   $env:PATH
  • Related