How to Run a C++ program inside a Rails 4 WebApp - c++

I'm interested in implementing a program written in C++ inside a Ruby on Rails 4 App.
The C++ app runs in console and works by giving it a file, it processes it and then it outputs another file.
I found 'Ruby Inline', a gem that allegedly allows the use of foreign code:
https://rubygems.org/gems/RubyInline
gem 'RubyInline', '~> 3.12', '>= 3.12.4'
Inline allows you to write foreign code within your ruby code. It automatically determines if the code in question has changed and builds it only when necessary. The extensions are then automatically loaded into the class/module that defines it. You can even write extra builders that will allow you to write inlined code in any language. Use Inline::C as a template and look at Module#inline for the required API.
According to the documentation, it allows the use of C and C++ programs like this:
require 'inline'
class MyTest
inline(:C) do |builder|
builder.include '<iostream>'
builder.add_compile_flags '-x c++', '-lstdc++'
builder.c '
void hello(int i) {
while (i-- > 0) {
std::cout << "hello" << std::endl;
}
}'
end
end
t = MyTest.new()
t.hello(3)
The problem is that I'm not entirely sure how to implement it with a larger C++ program made out of multiple files, I'm not proficient in C++.
This seems like a gem to add the C++ code inside a ruby script and the C++ program is made out of multiple files and folders.
Will Ruby Inline work for what I want to do or is there a better option out there?
Is there a way to call the C++ app directly without putting it inside a ruby file?
The file to be given to the C++ app will be uploaded via the web interface, how can I feed it to the C++ program so it outputs the result?

Ruby supports the functionality to run native commands using the ` character. For example, we have a C++ program below, that takes two arguments, and then prints to standard output both of them, concatenated together. The course code for this program can be seen below:
#include <iostream>
int main(int argc, char ** argv){
std::cout << argv[1] << argv[2] << std::endl;
return 0;
}
While the C++ code, really only needs to be compiled a single time, and this step wouldn't likely be necessary, we can compile it from within ruby by doing the following: (You can replace g++ with the compiler of your choice.) We will set the variable success to true if the command successfully compiles, false otherwise.
pathToSource = "your/path/to/file.cpp"
outputBinaryFile = "your/desired/output/file.bin"
success = system("g++ #{pathToSource} -o #{outputBinaryFile}")
Now that we have compiled our code, we can execute it by running the following in ruby:
word1 = "Hello"
word2 = "World"
commandOutput = `./#{outputBinaryFile} '#{word1}' '#{word2}'`
Which will set commandOutput to: "HelloWorld\n"
You may need to change small things such as the compiler depending on the system that you are running, but this should function for you on *NIX systems.

Related

Running the command line dot program from a Qt application generates no output, what is wrong?

I have an app that generates a dependencies.dot file which I then want to convert to an SVG image.
When I do that from a simple application like so:
int main(int argc, char * argv[])
{
system("dot -Tsvg ../BUILD/dependencies.dot > ../BUILD/dependencies.svg");
return 0;
}
It works great. The SVG image is present and working.
When I instead run it from my Qt application, the SVG file is created (by the shell), but it remains empty.
Any idea what could prevent dot from outputting data to its stdout?
Just in case, I also tried a cat to send the input through stdin instead of a filename:
system("cat ../BUILD/dependencies.dot | dot -Tsvg > ../BUILD/dependencies.svg");
And that didn't make any differences.
Also using the full path (/usr/bin/dot) did not help either.
Another test, I tried to use popen() and the first fread() immediately returns 0 (i.e. the mark of EOF).
It may not be Qt, but something is interacting with dot's ability to do anything. Any pointers on why that is would be wonderful.
Maybe an important note? I start my app. from a console, so stdin, stdout and stderr should all work as expected. I actually can see debug logs appearing there and other apps seem to work just as expected (i.e. My Qt app. can successfully run make, for example).
Here is an example of the resulting SVG (when I don't run it from within my Qt app):
For reference, the source code can be found on github. This is part of the snapbuilder. A tool that I use to run a build on launchpad. It's still incomplete, but it's getting there.
https://github.com/m2osw/snapcpp/tree/master/snapbuilder
The specific function to look for: project::generate_svg().
I still have no clue what side effect Qt has on system() that the dot command would fail. However, if using my own fork() + execve(), then it works.
I wanted a new process class for my environment, so I implemented that. This newer version is using FIFOs or directly opening closing files that it passes to the process.
...
// write the script in `std::stringstream dot` then:
//
std::string script(dot.str());
g_dot_process = std::make_shared<cppprocess::process>("dependencies");
g_dot_process->set_command("/usr/bin/dot");
g_dot_process->add_argument("-Tsvg");
g_dot_process->add_input(cppprocess::buffer_t(script.data(),
script.data() + script.length()));
g_dot_process->set_capture_output();
g_dot_process->set_output_capture_done(output_captured);
g_dot_process->start(); // TODO: check return value for errors
...
// and in output_captured()
//
void snap_builder::svg_ready(std::string const & svg)
{
std::string const svg_filename(...);
{
std::ofstream out;
out.open(svg_filename);
if(!out.is_open())
{
std::cerr << "error: \n";
return;
}
out.write(svg.c_str(), svg.size());
}
dependency_tree->load(QString::fromUtf8(svg_filename.c_str()));
}
Now the dot file is generated and displayed as expected.
This is rather strange since most everything else I've done with a simple system() call works as expected. There must be something about stdin or stdout that makes dot not do its work.

How to pass a value from a C++ executable to a Rails app?

I have a Rails app that runs a C++ executable from the command line. I'm able to print the C++ cout to the command line, but I'd like to assign it back to a variable, output = in a Rails controller.
Is this possible?
Below is a simplified example of my Rails controller action and C++ .cpp to help explain the question.
Rails controller:
def get_variable
system("cd ~/workspace/OutputTest/src && ./output.bin")
end
Note I've already compiled and created a C++ executable file named output.bin.
C++ file:
#include <iostream>
using namespace std;
int main() {
cout << "Hello world!!!";
return 0;
}
I'm familiar with Rails (not necessarily running files from the command line through Rails), but a complete newb to C++.
Any guidance would be very appreciated. If there is another approach I should be taking completely, that would also be very helpful to know.
I would prefer not to do this inline, as I'd like to do a lot more in C++ once I can solve this initial step.
UPDATE
The best solution I've come up with so far is writing a string to a .txt in C++, and then using File.read() in Rails. But it doesn't feel scalable, or give flexibility over data structure.
So I'm still wondering if there is a more straightforward way, like somehow keeping the value in memory for Rails to access it. Not sure though.
Maybe you have already tried this, but there is a backtick operator in ruby, which returns the output of a command as a string.
example:
def system_date
`date`
end
puts system_date #=> "Wed Nov 16 18:59:28 CET 2016"
in your case it would be
def get_variable
`~/workspace/OutputTest/src/output.bin`
end
The best idea I thought of is running the C++ app, piping (|) the input to rails (if that works) and doing $stdin.gets(). I'm not a ruby expert, and I haven't used it much, but I think it should work. Try
./cppapp | rubyapp
on a bash terminal.
You can capture an output of your programm with pipe:
test.cpp:
#include <iostream>
int main() {
std::cout << "Hello world!!!";
return 0;
}
Compile it: $ g++ test.cpp -o hello
test.rb:
var = IO.popen("./hello") do |cmd|
cmd.read
end
puts var
#=> "Hello world!!!"
More information about pipe reading can be found in documentation: IO.popen
You can use the back-tick operator to capture the output of command line executions in ruby.
irb(main):008:0> x = `echo foo`
=> "foo\n"

How to design a C++ GUI application that mostly runs tcl script

I am looking for a good approach to build a C++ GUI application. Its core is generating whole bunch of tcl code and execute it through Tcl C++ API (#include <tcl.h>). The GUI provides an easy way for users to complete those tcl scripting tasks.
In other words, inside each callback function associated with the GUI control, it's like using ostringstream to populate tcl code and passes it to tcl interpreter. Eg:
bool execTclProc1(options) {
ostringstream oss;
oss << "package require MyPackage \n";
string optionsForTcl = genOptionsForTcl(options);
oss << "myTclProc1 " << optionsForTcl << endl;
if(Tcl_Eval(interp, oss.c_str() == TCL_OK) {
// print out some messages to the GUI message window
}
...
}
The down side of this design:
Hard to debug tcl code error. Since every change in tcl code needs to re-compile the C code. Although a fast way is to write and test tcl code in tcl interactive shell. But a lot of tcl code is populated in C++, not hard-coded. So it's not so feasible.
Whole bunch of tcl code is written in C++ routines. This makes it hard to maintain.
I want to seek some insights from the community.
Can't you use the Tk toolkit called as library functions from C++?
Also, there is Tk/C++ - don't know how good it is. They overloaded operator- and use expression templates so that the C++ code like like Tcl. Pretty cool!

Running c++ in browser

I have written some basic c++ programs in one of my classes for school. I was wondering if it was possible to somehow virtually run the program in a broswer. I would like to post the program to my website. Once its posted, a person could access the program, run the program, and, interact with the program. I'm not trying to write C++ for my website, it would be more for an interactive portfolio.
Is this possible?
Use codepad, a website which lets you compile and share code online.
#include <iostream>
int main(int argc, char** argv) {
std::cout << "Hello, Stack Overflow!" << std::endl;
return 0;
}
There is also Google Native Client SDK that allows C++ code to run in browser. Microsoft Active X is also a viable option. I am only saying it is possible not recommended.
You can only run the program on your server, not on the client's machine.
At least not without downloading and manually executing it. Anything else would be an open door for malware...
I see two options, but both very overkill:
Write (or find) a C++ interpreter in JavaScript
Use a VM running an operating system (e.g. jslinux and demonstrate your programs there.
The sensible option is to just give people a way to view and download the source code, I guess.
Google chrome supports this: http://www.readwriteweb.com/cloud/2011/08/google-officially-announces-cc.php
But it's by no means "mainstream" or standards-based.
Another solution (codepad like) would be to use https://ideone.com/ which seems much nicer to use than codepad, more user-friendly, but does the same:
Allow you to write C++ (60 languages possibles) directly from the browser and compile it and render result in the browser (I tried using printf and it worked fine). Possibility of forking source code.
https://ideone.com/baYzfe
The following two programs are quite useful :
1) Ideone
2) Codepad
You can compile, run, and share code online in any browser.
You can use Emscripten to compile C++ to Javascript. Emscripten can compile LLVM bitcode to Javascript. Some demos of Emscripten can be found here, including a raytracer and a text-to-speech engine that was compiled from C++ to Javascript.
To run x86 binaries in a web browser, you could also use an emulator such as v86. This is one possible way to compile and run C++ programs in a browser.
One of the best sites for running C++ and other multiple languages online is Repl.it
This example: repl.it/#abranhe/stackoverflow
#include <iostream>
int main() {
std::cout << "Hello Stackoverflow\n";
return 0;
}
One of the biggest pros it has is that you can work with multiple files, working with header (header.h) files etc. None of the below websites provide this option:
Codepad.org
JSLinux
IDEone
I really recommend it! You will love it!
Also wanted to add Google Colab here as an option:
Cell 1:
%%writefile hello.cpp
#include <iostream>
int main(int argc, char** argv) {
std::cout << "Hello, Stack Overflow!" << std::endl;
return 0;
}
Cell 2:
%%script bash
g++ hello.cpp -o test
ls -laX
./test

Communicating between a ruby script and a running c++ program

I have a c++ program which performs one function. It loads a large data-file into an array, receives an array of integers and performs a lookup in that array, returning a single integer. I am currently calling the program with each integer as an argument, like so:
$ ./myprogram 1 2 3 4 5 6 7
I also have a ruby script, and I would like this script to utilize the c++ program.
Currently, I am doing this like so.
Ruby Code:
arguments = "1 2 3 4 5 6 7"
an_integer = %x{ ./myprogram #{arguemnts} }
puts "The program returned #{an_integer}" #=> The program returned 2283
This is all working properly, but my problem is that each time ruby makes this call, the c++ program has to reload the data-file (which is over 100mb) - very slow, and very inefficient.
How can I rewrite my c++ program load the file only once, allowing me to make many lookups via a ruby script without reloading the file each time. Would using sockets be a sensible approach? Writing the c++ program as a ruby extension?
Obviously I am not an experienced c++ programmer, so thanks for your help.
A possible approach is to modify your C++ program so that it takes its input from the standard input stream (std::cin) instead of from the command line parameters, and returns its result through the standard ouput (std::cout) instead of as main's return value. Your Ruby script would then use popen to launch the C++ program.
Assuming the C++ program currently looks like:
// *pseudo* code
int main(int argc, char* argv[])
{
large_data_file = expensive_operation();
std::vector<int> input = as_ints(argc, argv);
int result = make_the_computation(large_data_file, input);
return result;
}
It would be transformed into something like:
// *pseudo* code
int main(int argc, char* argv[])
{
large_data_file = expensive_operation();
std::string input_line;
// Read a line from standard input
while(std:::getline(std::cin, input_line)){
std::vector<int> input = tokenize_as_ints(input_line);
int result = make_the_computation(large_data_file, input);
//Write result on standard output
std::cout << result << std::endl;
}
return 0;
}
And the Ruby script would look like
io = IO.popen("./myprogram", "rw")
while i_have_stuff_to_compute
arguments = get_arguments()
# Write arguments on the program's input stream
IO.puts(arguments)
# Read reply from the program's output stream
result = IO.readline().to_i();
end
io.close()
Well,
You could go about this a number of different ways.
1) A simple, potentially ugly way to do this is to have your c++ run and intermittently check for a file, have your ruby script produce said file containing your arguments. Your C++ program would then use the contained arguments returning it's result to a result file which you could wait on within your ruby script... This is obviously HACK TASTIC but it's uber simple to implement and would work.
2) Expose your c++ code as a c extension to ruby. This is not as hard as it's sounds especially if you use RICE and would provide significantly less hackie solution.
3) If your c++ can be exposed through a c header file then it's almost trivial to construct a bridge using FFI. Jeremy Hinegardner gave a good lecture on constructing FFI interfaces at rubyconf heres the screencast
4) D-Bus provides an application communication bus, you could alter your C++ app to take advantage of said event bus and pass messages from your ruby using ruby-dbus
There are of course a thousand other routes... Maybe one or the other of these could prove viable :)
Cheers!