Sublime Forum

[Windows] Bizarre Issue with Compiling C++

#1

When I compile a C++ program on Windows, I get no errors. If the program only entails “cout” (output), everything works fine. But when there’s “cin” (input) involved, things get weird.
The program will compile with no errors, but the program will never get passed asking the user for their input. Say the user is prompted to enter a number. I’ll enter a number, press enter, and then nothing will happen. It’ll just make a new line in the terminal. I can then literally write in the terminal, creating new lines and entering any kind of character.
Sublime thinks that the program is in the middle of building, offering me a “cancel build” option. If I don’t cancel the build, nothing will happen.
If I try to run the .exe program in an external terminal (by clicking on the exe in Windows’ file manager), the terminal will just close after I press “enter” following the cin input.

I’m new to this, so I’m sure there’s some more information I should provide. Please let me know and I’ll gladly do so . Thanks!

0 Likes

#2

Sublime doesn’t connect the stdin of the program to execute to anything, so regardless of the language or platform you’re on, your program will hang forever when it hits anything that wants to read from stdin because there’s no direct way to feed it any data.

The problem is exacerbated on Windows because such a program sits in the background patiently waiting, and Windows locks executables of running programs, so any further attempts to build the program will throw access errors at the link stage.

To run an interactive program like this you need extra setup; you either need to modify your build system to launch an external terminal and run your program there, or use the Terminus package in your build system.

0 Likes

#3

Thanks so much for replying. I’m new to this - just starting computer science courses - and have no idea how to modify the build system & never heard of the terminus package. I’ll look into it of course, but do you have any recommended documentation I can look at to learn all of this?

PS: Would opening the .exe in Windows’ terminal constitute an “external terminal”? Like I’ve said, I’ve tried that and the terminal keeps closing immediatly after I enter the stdin input.

0 Likes

#4

The package in question is the Terminus package, which you can install via Package Control. It adds the ability to open a command prompt to Sublime. Running external programs in there will work as expected.

As it transpires I’m currently working on a video series on Build Systems in Sublime and the first video on build system basics dropped this morning. A video covering this exact topic has been recorded but isn’t going to drop for another month. I sent you a PM with a link to a rough excerpt of this particular part.

The official documentation has a section covering build systems that may help. The unofficial documentation is also a good resource.

It does, but the problem you’re seeing there is that once the program is complete, the command prompt closes, which makes the window go away. The quick fix is to make your program wait for you to press return before it exits, or you can craft the command line that launches the terminal so that it runs your program followed by pause to wait on your behalf.

1 Like

#5

You could also run cmd.exe first, and then CD to the directory of the executable, and then type the name of the executable. This requires no code changes.

0 Likes

#6

Thank you so much. The videos are great! Really nice of you to go out of your way to send me the clip. Subscribed on YT :smile:

I successfully created a build system, but I am having an issue running it with terminus. Specifically, I can only make the build work with shell_cmd but can’t get it to work with cmd.
Here’s the build system I made with shell_cmd, which works without terminus:

"shell_cmd": "g++ -o output \"$file\" ; ./output",

This works just fine, producing the output from my code, and “hanging” by the input for the reasons you’ve described.
But Terminus, as you’ve explained in your video, only works with cmd. The first part of my build system works just fine. If my build system is:

 "target": "terminus_open",
 "cmd": ["g++", "-o", "output", "$file"]

The terminal will open in a new window and return

 process is terminated with return code 0

Obviously, since there’s no command to run the executable, it won’t run. But it compiled correctly (and terminus worked as expected).
But when I add the command to run the executable, and the build reads

 "cmd": ["g++", "-o", "output", "$file", "./output"],

A terminal opens and returns:

 g++: fatal error: input file ‘output’ is the same as output file                                           
 compilation terminated.
 process is terminated with return code 1.

So I’m obviously phrasing something wrong in the command, but since the same structure works with shell_cmd and - sans “./output”- runs fine in cmd, I’m not sure what the issue is.

P.S. I’m back at school so I’m using my Chromebook (Crostini/Linux), not a Windows computer.

1 Like

#7

Thanks so much for the kind words, glad I could help!

When builds use shell_cmd, behind the scenes the system’s command interpreter (bash on Linux/MacOS or cmd on Windows) is executed and told “please execute this command”. The command interpreter knows how to do things like chain multiple commands together and such.

In contrast, cmd indicates that the first item in the list is the program to execute and the remainder of the items are arguments for that program when it’s executed. Terminus works the same way, and so unless the program being executed (here g++) knows how to run multiple commands, that doesn’t work. Essentially you’re just providing extra arguments to g++ and it gets confused about what you meant.

The normal advice would be that if you want to run multiple commands or otherwise take advantage of the features of the command interpreter (such as piping output and input) you should use either shell_cmd, or use cmd and also provide "shell": true in the build, which makes the internal exec command convert the cmd into a shell_cmd behind the scenes (more or less).

Terminus only supports cmd and doesn’t handle the "shell": true part of the build, so to use Terminus like this you need to manually do behind the scenes what shell_cmd is doing, which is to run the command interpreter for the system and give it a command to run.

An example of that would be:

{
    "target": "terminus_open",

    "cmd": ["/usr/bin/env", "bash", "-c", "g++ -o \"${file_path}/${file_base_name}\" \"${file}\" && \"${file_path}/${file_base_name}\""],
    "working_dir": "${file_path}",

    "auto_close": false,

    "selector": "source.c, source.c++",
}

Here we’re telling Terminus to use /usr/bin/env to locate the bash interpreter, and then execute bash and provide it two arguments; the first is -c to tell it that it should execute the next argument as a command, and the second is the actual command line (essentially what you’d put into shell_cmd). The /usr/bin/env part is a safeguard that bash will be found; you could leave that part out and start the command with bash directly as well if you know that bash is in the PATH.

The example here uses ${file_path}/${file_base_name} to create an executable that’s the same name and location as the input source file (but with no extension), and the && instructs bash to only try to execute the program if it compiled correctly. You can use a hardcoded name as in your example above as well; doing it as above ensures that if you’re working on multiple programs once you compile something, it remains there for you to run manually later.

The above example is for Linux; if you want to do something like this on MacOS you would instead use:

"cmd": ["/usr/bin/env", "bash", "-l", "-c", "....."]

Essentially the same as above with with the addition of an extra argument to tell Bash to run as a login shell so that on MacOS it will pick up the correct environment.

For windows, the command would be:

"cmd": ["cmd", "/c", "..."]
0 Likes

#8

How can I send this command
"cmd": "g++ -std=c++17 -Wall \"${file}\" -o \"${file_path}/${file_base_name}\" && \"${file_path}/${file_base_name}\"",
to terminus.
I am trying to create a c++ build system but it doesn’t seem to work.

{
"target": "terminus_open",
"auto_close": false,
// "title": "Cpp Output",
// "tag": "cpp",
"cmd": "g++ -std=c++17 -Wall \"${file}\" -o \"${file_path}/${file_base_name}\" && \"${file_path}/${file_base_name}\"",
//"file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
"shell":true,
"working_dir":"$file_path",
"selector":"source.c++, source.cpp, source.cc, source.cxx",

}

0 Likes

#9
2 Likes

#10

please help me i can’t generate output in my screen . Please tell considerable solution.

0 Likes