CMake: Bundling a Console Application in MacOS c++ - c++

I am building a MacOS c++ application in CMake that is a terminal program with a few associated libraries. I would like bundle the executable because customers are familiar with that. However, then opening the bundled .app the terminal will not open and the program disappears immediately even if I request input.
For example, the application main.cpp
#include <iostream>
int main()
{
int x;
std::cout << "Hello World!\n";
std::cin >> x;
std::cout << "You said " << x << "\n";
return 0;
}
can be made up with CMakeLists.txt file:
cmake_minimum_required(VERSION 3.4)
project(hello_world)
SET(CURRENT_TARGET hello)
add_executable(${CURRENT_TARGET} MACOSX_BUNDLE main.cpp)
But if I double-click the hello.app file it creates, it closes immediately. Is there a way to fix this?

Related

QtCreator with Intel OneAPI SYCL

I started my study with OneAPI SYCL but I normally use QtCreator as my IDE. I did a HelloSYCL project with CMake and works fine in the terminal and in the VSCode with OneAPI Extension as well, but didn't work in the QtCreator.
Every time I want to use SYCL I need to start ONEAPI environment with ". /opt/intel/oneapi/setvars.sh", but I don't know how to do it with QtCreator
Here is the way I'm compile
mkdir build; cd build
cmake -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -G Ninja -S .. -DCMAKE_PREFIX_PATH="/opt/intel/oneapi/compiler/latest/linux/cmake/SYCL/" -DSYCL_INCLUDE_DIR=/opt/intel/oneapi/compiler/latest/linux/include/sycl -DSYCL_LIBRARY_DIR=/opt/intel/oneapi/compiler/latest/linux/lib
cmake_minimum_required(VERSION 3.22)
project(testSYCL LANGUAGES CXX)
if(UNIX)
set(CMAKE_C_COMPILER icx)
set(CMAKE_CXX_COMPILER dpcpp)
endif(UNIX)
list(APPEND CMAKE_MODULE_PATH "/opt/intel/oneapi/compiler/2021.4.0/linux/")
list(APPEND CMAKE_MODULE_PATH "/opt/intel/oneapi/compiler/2021.4.0/linux/cmake/SYCL/")
find_package(IntelDPCPP REQUIRED)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if (NOT CMAKE_BUILD_TYPE)
message(STATUS "No build type selected, default to Release")
set(CMAKE_BUILD_TYPE "Release" CACHE PATH "Build Type" FORCE)
endif()
add_executable(testSYCL main.cpp)
#include <iostream>
#include <iomanip>
#include <CL/sycl.hpp>
int main()
{
for ( const auto& plataform : sycl::platform::get_platforms() ) {
std::cout << "=========================================================\n";
std::cout << std::setw(25);
std::cout << plataform.get_info<sycl::info::platform::name>() << "\n";
std::cout << plataform.get_info<sycl::info::platform::vendor>() << "\n";
std::cout << "Plataform: " << plataform.get_info<sycl::info::platform::version>() << "\n";
for ( const auto& device : plataform.get_devices() ) {
std::cout << "Devices\n";
std::cout << "Name: " << device.get_info<sycl::info::device::name>() << "\n";
std::cout << "Max Compute Units: " << device.get_info<sycl::info::device::max_compute_units>() << "\n";
std::cout << "Max Work Group Size: " << device.get_info<sycl::info::device::max_work_group_size>() << "\n";
std::cout << "Max Clock Frequency: " << device.get_info<sycl::info::device::max_clock_frequency>() << " MHz \n";
}
}
}
QtCreator CMake Error
QtCreator Custom Compiler added
The answer depends on the contents of setvars.sh. I assume this is a simple script setting environment variables.
One way to mimic it in QtCreator is to define a custom kit.
Go to Tools/Options/Kits. Highlight any kit you use and press "clone". Then, add to it manually the necessary environment variables in the field "Environment". Use this kit for your SYCL projects. This will work if your problem is caused by a compiler error.
If the problem occurs while running a program inside QtCreator, look at build/running options:
There you'll easily find options for changing the runtime or compile-time environment

C++ stream becomes bad if called in multiple shared libs and libstdc++ static linking is enabled

I compiled 2 shared libs with --static-libstdc++ enabled.
The 2 shared libs have the same function f, which just outputs a string and an integer to stdout.
Main program will load the 2 shared libs using dlopen, and call the f in it using dlsym.
However, the second loaded shared lib failed to output the integer and the C++ stream cout becomes bad & fail.
ADD: After discussion, I know this is normal... However, I want to change my question to: what implementation of libstdc++ caused this issue? Is there any shared global state? I think if there is no shared global state, it shouldn't be a problem. I wrote the similar program in Windows by static linking to VCRuntime and using LoadLibrary, and it works normally. So why libstdc++ is designed like this?
The following is the code for 2 shared libraries. (They share the same code)
They will just cout a string and a integer.
// dll.cpp
#include <iostream>
using namespace std;
extern "C" void f()
{
cout << "hi" << 1 << endl;
bool is_eof = cout.eof();
bool is_fail = cout.fail();
bool is_bad = cout.bad();
cout.clear();
cout << endl;
cout << "eof: " << to_string(is_eof) << endl;
cout << "fail: " << to_string(is_fail) << endl;
cout << "bad: " << to_string(is_bad) << endl;
}
This is the main program, which loads the shared libs and calls their f functions.
// main.cpp
#include <iostream>
#include <dlfcn.h>
#include <cassert>
using namespace std;
using fn_t = void(void);
void call_f_in_dll(const char *dll_path)
{
auto dll = dlopen(dll_path, RTLD_LAZY);
assert(dll);
fn_t *fn = (fn_t *)dlsym(dll, "f");
assert(fn);
fn();
dlclose(dll);
}
int main()
{
call_f_in_dll("./libmydll.so");
cout << endl;
call_f_in_dll("./libmydll2.so");
return 0;
}
Here's the CMakeLists.
# CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project (TestGCC)
add_link_options(-static-libgcc -static-libstdc++)
add_library(mydll SHARED dll.cpp)
add_library(mydll2 SHARED dll.cpp)
add_executable (main main.cpp)
target_link_libraries(main dl)
And the output is:
hox#HOX-PC:~/repos/test-gcc/out$ ./main
hi1
eof: 0
fail: 0
bad: 0
hi
eof: 0
fail: 1
bad: 1
Notice the second part, there is no 1 after hi and fail & bad become 1.
You can checkout the code here: https://github.com/xuhongxu96/dlopen-iostream-issue
Finally I found a way to resolve the issue in Linux (GNU Extensions).
Use dlmopen which provides better isolation btw objects.
auto dll = dlmopen(LM_ID_NEWLM, dll_path, RTLD_LAZY);
Great thanks for all commenters!
Still welcome to explain the details about what the conflict states are.

How to resolve Ninja c++ build and execution

I have a C++ project based on CMake that uses Ninja. It's been build and ran using eclipse for C/C++. My current machine is a Mac OS.
The file:
#include <iostream>
#include <exception>
#include <string>
#include <stdexcept>
#include <vector>
#include <cmath>
using namespace std;
class Server {
private:
static int load;
public:
static int compute(long long A, long long B) {
load += 1;
if(A < 0) {
throw std::invalid_argument("A is negative");
}
vector<int> v(A, 0);
int real = -1, cmplx = sqrt(-1);
if(B == 0) throw 0;
real = (A/B)*real;
int ans = v.at(B);
return real + A - B*ans;
}
static int getLoad() {
return load;
}
};
int Server::load = 0;
int main() {
int T;
cin >> T;
while(T--) {
long long A, B;
cin >> A >> B;
/* Enter your code here. */
try{
cout << Server::compute(A, B) << endl;
} catch(invalid_argument e){
cout << "Exception: A is negative" << endl;
} catch(bad_alloc &e){
cout << "Not enough memory" << endl;
} catch(exception &e){
cout << "Exception: ";
cout << e.what() << endl;
} catch(...){
cout << "Other Exception" << endl;
}
}
cout << Server::getLoad() << endl;
return 0;
}
Build info:
cmake --build . -- -v
[1/2] /Library/Developer/CommandLineTools/usr/bin/c++ -O3 -DNDEBUG -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk -MD -MT CMakeFiles/deleteme.dir/deleteme.cpp.o -MF CMakeFiles/deleteme.dir/deleteme.cpp.o.d -o CMakeFiles/deleteme.dir/deleteme.cpp.o -c ../../deleteme.cpp
[2/2] : && /Library/Developer/CommandLineTools/usr/bin/c++ -O3 -DNDEBUG -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/deleteme.dir/deleteme.cpp.o -o deleteme && :
Build complete (0 errors, 0 warnings):
When I run:
Building in:
cmake --build . -- -v
ninja: no work to do.
Build complete (0 errors, 0 warnings):
It does not give me the chance to input the values. It just skips everything and finishes execution. If I put a cout right at the beginning, then the program works as expected.
Why is this happening?
Ps: The project complete path was removed from here for safety reasons. And yes, my project was created with the name 'deleteme'.
Pss: I took this snippet from HackerRank for studing purposes, so It should be fine. I've only added the try/catch and method call.
You are confusing building your program with running your program.
When you run the command cmake --build . -- -v, cmake will build your project. That means it will launch the appropriate tools to compile and link your program, which will produce an executable called deleteme somewhere in your build directory.
The subsequent invocation of the same command correctly reports that no work needs to be done (since you presumably haven't modified any of the source code between invocations).
To be clear, normally this will not run your program, which is why you don't get a prompt to input any values.
To run your program, which, if I understand correctly is what you are trying to do, simply run the executable deleteme that was produced by the build process. You will most likely find this executable in the build directory, that is, the directory where you ran the cmake --build . command. (Depending on your CMake project structure, you may also find it in a subdirectory of your build directory.)
I've figured It out how to solve this. I don't know what have caused It. It looks like ninja is not need if you have properly configured your environment variables, related to your compiler, inside Eclipse.
After doing that, everything works fine.

glfwInit() causes access violation

#include <glfw3.h>
int main()
{
glfwInit();
return 0;
}
When I try to run glfwInit() it throws an access violation and says "Frame not in module". 1
This error is shown because the error is produced in a non debuggable source code.
The most probable cause is that DLL was not loaded.
Try to add GLFW bin path to one of the PATH environment variable, or copy DLL to executable path .
Try calling glfwGetVersion to check DLL is loaded before call glfwInit.
int major;
int minor;
int rev;
glfwGetVersion(&major, &minor, &rev) ;
cout << major << "." << minor << "." << rev<< endl;

How to compile and run C++0x with GCC/G++ in Eclipse CDT?

I am trying to figure out how to use the upcoming C++ release 0x. It should be available in GCC 4.3+ with using the gcc std=gnu++0x option.
My simple thread program using 0x compiles in Eclipse CDT with std=gnu++0x added in Project > properties > C/C++ Build > Settings > Miscellaneous > Other flags.
#include <iostream>
#include <thread>
using namespace std;
void hello()
{
cout << "Hello Concurrent World!" << endl;
}
int main()
{
cout << "starting" << endl;
thread t(hello);
t.join();
cout << "ending" << endl;
return 0;
}
The program only prints "starting" and returns 0. Does anyone know why it does not run the hello function threaded?
To use threads you also need to link against the threading library.
In case you haven't done that add -lpthread to your command line or in your case to other flags field.
The command line execute (visible in your console window in eclipse) should look like this:
gcc -std=gnu++0x -lpthread <source_file_name>.cc