-2

I'm making a program that depends heavily on another C binary. Since I don't feel like learning how to use headers and what not yet, I wanted to take the simple rout and just run a pre-compiled binary from the same folder in my cpp program.

Right now, my folder is setup like this: It has main.cpp, CMakeLists.txt, and the ibootim binary. Inside of main.cpp, how would I call ibootim?

From coding in python, it's taught me that I should be able to run

system("./ibootim");

but that doesn't work. Terminal tells me that there's no file found. Obvioiusly if I were to put the entire path to that binary, it would work. However, if other users were to download this, it would not work for them since they don't have the same computer, username, etc. as I do.

So my first question, my primary concern would be:

How do you run another binary that's in the same directory in a c++ program?

If this isn't possible for some reason, then I can try downloading ibootim from source and maybe using the header file:

How do you execute code from a C header in a C++ program?

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
  • "How do you execute code from a C header in a C++ program?" You don't. This isn't Python. Different rules apply. – tadman Oct 13 '22 at 06:58
  • "How do you run another binary that's in the same directory in a c++ program?" You don't. You need to *install* your program and if it has dependent binaries, you install those, too, at a predictable location. – tadman Oct 13 '22 at 06:58
  • @tadmanWhat do you mean by install? Where am I supposed to put the binaries? How do I include the functionality of a binary in c++? Imagine this as if you only have the directory that c++ file is in and that's it. – The Sogie Man Oct 13 '22 at 07:03
  • That's not how compiled code works. The source directory should have source and only source. Any binary dependencies need to be packaged up separately. Most C++ projects have some kind of "install" step, like `make install` or whatever build system you're using, that will move the resultant binary(ies)/library(ies) and other dependencies into their proper place. – tadman Oct 13 '22 at 07:04
  • 1
    `system()` should work. Perhaps your working directory doesn't match the application directory? – HolyBlackCat Oct 13 '22 at 07:04
  • Remember, people generally don't download C++ code and then have at it with the compiler, they download an already compiled version, such as a "tarball", or, better, an installer package (.deb, .dpkg, .msi, etc.) that they can install from. – tadman Oct 13 '22 at 07:05
  • 1
    @HolyBlackCat I just realized why it didn't work. It's because I built the binary in a different directory than the ibootim binary. I might've just made this post for nothing... – The Sogie Man Oct 13 '22 at 07:05
  • @tadman What do you mean? Are you saying that the optimal choice is to have it all in one binary? If so, where should I start in using a C header in a C++ program? – The Sogie Man Oct 13 '22 at 07:07
  • It's not about headers, it's about *packaging*. Consider what happens when your app is installed, and the source is removed, or was never there to start with. This is why installers exist. If you're just working on a dev project in XCode, you could use something like `SRCROOT` to compute where to look, such as having a separate `bin/` directory in your project root. – tadman Oct 13 '22 at 07:09
  • 1
    What is `ibootim` and where does it come from? – tadman Oct 13 '22 at 07:10
  • 1
    @tadman ibootim is a program written in C that allows a user to convert a png into an iBoot image. This is used on the iPhone for people to send custom picture to the iPhone before it boots. Many other scripts, usually SSH scripts use this ideology to set custom boot logos. You can find the original source on GitHub here: https://github.com/realnp/ibootim – The Sogie Man Oct 13 '22 at 07:12
  • If you're using XCode you can usually make a secondary executable target and bundle that in the project as well if the license permits. The path of the resultant executable will be a `#define` variable, or something you'll need to establish in the installer environment via a `.plist` setting, potentially. – tadman Oct 13 '22 at 07:14
  • 1
    Ideally you can ditch the external executable altogether and rework that into a library you can just drop in. Although this has an annoying up-front cost, this is *considerably* less fuss going forward. – tadman Oct 13 '22 at 07:15
  • @tadman I do have XCode! However, I have no idea how to do that, nor do I know what you're talking about. – The Sogie Man Oct 13 '22 at 07:15
  • There's not a whole lot of code there, so you could probably switch out the `main()` function and write a function that does the same thing you can use on the C++ side. This would result in a way cleaner build with no external executable dependencies, and you won't have to deal with the cross-platform issues you'd otherwise face when bundling a pre-built executable. – tadman Oct 13 '22 at 07:17
  • @tadman So you're saying that I should have two functions in my cpp file, one for ibootim and one for the rest? If so, is there a way that I can get a basic tutorial on how to do that? Or a guide that does something similar? – The Sogie Man Oct 13 '22 at 07:18
  • 1
    I had a quick look at the code you referenced, and it's basically two files full of functions and such, and it hasn't changed in a while. That's good for you, since adding it as a library target should be pretty easy. The only tricky part is removing `main()` and working in an exported library function you can call from the C++ side of things. Once this is done, instead of calling another executable, you just call a function from that library. Way cleaner, and error handling is going to be a lot easier. – tadman Oct 13 '22 at 07:19
  • @tadman Cool! So you're saying that I should take all of the files except for the make file and all of that junk away, remove `main()` from ibootim.c, and copy and paste that into my project? Or are you saying something diferent that I'm not understanding? – The Sogie Man Oct 13 '22 at 07:23
  • 1
    The license seems pretty permissive, though do pay attention to the requirements of it, you may need to include that in any "About" text in your app if you distribute it. Other than that, you can wrap that up int a tidy little library that does exactly what you need. Copy or otherwise transpose that source over into a separate directory, build a library from it, and you're good to go. Keeping it as a separate target can help if it needs different compiler settings, etc. plus helps focus your main app on its core code. – tadman Oct 13 '22 at 07:27
  • @tadman Thanks for your help. One more thing, how would I actually do this? Like, what files do I need to move, where do I need to move them, what include path would I use, what would my include notation be in the code (I don't know if that's the right term, but it's the `#include` line), and how would I impliment the functions in the code? – The Sogie Man Oct 13 '22 at 07:29
  • 1
    _Since I don't feel like learning how to use headers and what not yet, I wanted to take the simple rout and just run a pre-compiled binary from the same folder in my cpp program._ Are you still convinced that the latter option is the easier one? – Scheff's Cat Oct 13 '22 at 07:31
  • 2
    @Scheff'sCat Nope. I'm not doing that anymore. I'm doing what tadman has suggested for me to do. – The Sogie Man Oct 13 '22 at 07:32
  • 1
    @tadman I just got finished copying the contents of ibootim.c into my program, keeping the copyright notice at the top of course. However, there's one error. it's in the void `path_add_index`, on the line that says `char *raw_path = alloca(raw_path_length + 1);`. The error in VS Code states, "a value of type "void *" cannot be used to initialize an entity of type "char *"C/C++(144)". Is there a fix? – The Sogie Man Oct 13 '22 at 08:19
  • If you've gotten through the tough part, that's great, though what you're asking sounds like a separate question, so maybe open up a new one and focus on that. – tadman Oct 13 '22 at 16:03

2 Answers2

0

For Windows, you can use GetModuleFileNameW() to get the absolute path to the running exe even if the working directory is different from the exe's directory. Then, you can use PathRemoveFileSpecW() to remove the filename from the path to get the exe's directory path. Then, you can use ShellExecuteW() to launch the exe with the filename you want while telling the function what directory to look in for the exe.

Here's a command-line example:

#include <windows.h>
#include <shlwapi.h>
#include <iostream>
#include <string>
#include <cwchar>
#include <cstdlib>
#include <cstdint>
#include <stdexcept>
#include <clocale>

using namespace std;

wstring get_exe_dir()  {
    wchar_t buffer[65537] = {L'\0'};
    if (!GetModuleFileNameW(NULL, buffer, sizeof(buffer))) {
        MessageBox(NULL, "GetModuleFileNameW length error", "EXE path is too long!", MB_OK);
        throw length_error("");
    }
    wcout << buffer << L'\n';
    PathRemoveFileSpecW(buffer);
    wcout << buffer << L'\n';
    return buffer;
}

int main() {
    setlocale(LC_CTYPE, ".OCP");
    const wstring exe_dir = get_exe_dir();
    const intptr_t result = reinterpret_cast<intptr_t>(ShellExecuteW(NULL, L"open", L"\"other.exe\"", NULL, exe_dir.c_str(), SW_SHOWNORMAL));
    if (result < 33) {
        MessageBox(NULL, "Error launching other.exe", "Launch error", MB_OK);
        return EXIT_FAILURE;
    }
}

// g++ -Wall -Wextra exe_path.cc -o exe_path -O3 -s -lshlwapi

Maybe Mac has a similar function. I see _NSGetExecutablePath(). For shellExecute(), I see this answer that might help. But, perhaps system() is fine on Mac where it doesn't spawn another terminal window like it does on Windows.

Shadow2531
  • 11,980
  • 5
  • 35
  • 48
-2

In c++ if you want to use a binary you can use std::system() function.

But to do this the binary must be on the PATH. If your binary is not on the path you can do something like this.

#include <iostream>

int main(){
#if _WIN32
    std::system("./mybinarie.exe");
#else
    std::system("./mybinarie");
#endif

return 0;
}

Starting the shell with std::system will ensure that you are in your working folder and that if the binary is in the working folder it should work.

  • `std::system` accepts a single argument. The right macro to check for Windows is `_WIN32`. I don't like the idea of invoking the shell for this, I'd instead find the current directory and create the full path manually ([or use `realpath`](https://stackoverflow.com/q/45124869/2752075)). – HolyBlackCat Oct 13 '22 at 10:55