How to add path an included library in kernel? - c++

I found many example, how to add this in host on C, but syntax C++ differ than C. I want to add external library in my kernel file.
It's part of my code:
std::ifstream sourceFile(name);
std::string sourceCode(
std::istreambuf_iterator<char>(sourceFile),
(std::istreambuf_iterator<char>()));
Program::Sources source(1, std::make_pair(sourceCode.c_str(), sourceCode.length() + 1));
// Make program of the source code in the context
Program program = Program(context, source);
// Build program for these specific devices
errcode = program.build(devices);
if (errcode != CL_SUCCESS)
{
cout << "There were error during build kernel code. Please, check program code. Errcode = " << errcode << "\n";
cout << "BUILD LOG: " + program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(devices[0]) + "\n";
getchar();
return;
}
// Make kernel
Kernel kernel(program, "vector_add");
How to add path of external library in this code?
In the next step i think, that need to add the second source in Program::Sources. Has anyone written this?

Based on OpenCL 1.2 specification (also the same for 2.0),
-I dir
Add the directory dir to the list of directories to be searched for header files.
You cannot include any ".cl" into another ".cl", but you can #include "Header.h" as much as you want where you can havesome functions or #define, etc.
Note that the code in those header must be in OpenCL C similar to your kernel (except if using OpenCL 2.2, where you can use OpenCL C++).
And lastly, except if you use OpenCL 2.0 and greater, you can't call kernel function inside a kernel, so they must be ordinary function void foo().
So in your case, you could do this:
Program program = Program(context, source);
errcode = program.build(devices, "-I C:\Path\To\My\Include\Header);
And to answer your second question
In the next step i think, that need to add the second source in Program::Sources. Has anyone written this?
You can push_back sources.push_back({ kernelSource.c_str(), kernelSource.length() + 1 }); as much kernel source code as you want into a single sources vector that you provide to the program. But at the end, you can make multiple kernels with this program, since you need to provide a single kernel name per cl::Kernel such as:
Kernel kernel_add(program, "vector_add");
Kernel kernel_sub(program, "vector_sub");
So that mean kernel_add and kernel_sub are build in same time, but they are two different kernels at the end.

Related

How can I use C++ to write to an opened terminal?

I am trying to communicate with a program (xfoil) and read and write to its command line. Xfoil can take many parameters in its built in terminal.
I can open the program using system("path") but how do I input more commands to the opened xfoil terminal? Once I can do that I can do all that I need to do with the terminal commands.
Tiny Process Library is a good library for interacting with processes.
Checkout example 6 and 7 for giving commands to a process. https://gitlab.com/eidheim/tiny-process-library/blob/master/examples.cpp
How can I use C++ to write to an opened terminal
On linux, there are 7+ steps:
1) open a terminal
I find ctrl-alt t most convenient
press and hold ctrl and alt, then press t
There is also a selection LXTerminal on a mouse menu
Note - There is a way for your program to open a 'default' terminal,
and c++ can use the technique, but it is not c++, and I always seem to
need to change the defaults for my use.
2) using the terminal, you manually find the name of the terminal by:
type the command "tty" into the terminal
Typical response on my system:
hostname#username:~$ tty
/dev/pts/1
The terminal name is always of the form "/dev/pts/x" on my Linux system, where x is a number.
3) For my programs (that use a second terminal), my code accepts the x portion (of the terminal response) as command parameter 1, and uses that parameter to create a path file name (PFN) to the terminal.
std::string aTermPFN = "/dev/pts/"; // partial address
aTermPFN += argv[1]; // ouput tty identified by argv[1]
// creating /dev/pts/<argv[1]>
// thus creating PFN of "/dev/pts/1"
4) My code typically provides a confirmation of the number during creation. (recommended)
std::cout << "accessing '" << aTermPFN
<< "' with std::ofstream " << std::endl;
5) and then creates (or attempts to create) the ofstream object
std::ofstream* ansiTerm = new std::ofstream(aTermPFN);
6) and perform a few checks on it ...
if (!ansiTerm->is_open())
{
std::cerr << "Can not access '" << aTermPFN << "'" << std::endl;
assert(0); // abort
}
7) When done with term, be sure to clean up
ansiTerm->close();
delete ansiTerm;
// you can avoid the delete if you use an appropriate smart pointer.
Now all output to that 2nd terminal uses the 'ansiTerm' object, I happen to use a more generic term in that code (not a pointer, but reference) : "termRef".
Examples of use
// mostly, in the app where these sample exist, I output text at computed
// screen locations
// ansi terminals provide goto row col ansi functions
// the style is simply position the cursor,
termRef << m_ansi.gotoRC(3, col) << ss.str() << std::flush;
// then output text-----------------^^^^^^^^ (ss is stringstream)
// ansi terminals can clear
void clearScr() { termRef << m_ansi.clrscr() << std::flush; }
// ansi terminals can draw simple borders (not-fancy)
{ // across top gotoRC (int row, int col )
termRef << m_ansi.gotoRC ( tlcRow, tlcCol+1);
for ( int i=0; i<borderWidth; ++i) termRef << m_acs.HLINE;
termFlush();
}

How to fix CopyFile() error 5 - access denied error

I am trying to write a copy file function that can be used on both Linux and Windows. It works on Linux, but on Windows, I get error code 5 when trying to use the WinApi function CopyFile().
In header File.h
This is the custom defined function in the File namespace that I should be able to use on both Linux and windows.
class File
{
public:
static bool copyFile(std::string source, std::string destination);
private:
}
In File.cpp
For Linux it is simple:
#ifdef __unix__
#include "File.h"
bool File::copyFile(std::string source, std::string destination)
{
std::string arg = source + " " + destination;
return launchProcess("cp", arg);
}
#endif
In the Windows specific block of code, I use the WinAPI (#include < windows.h >) function CopyFile(). This accepts LPCWSTR data types instead of strings. To overcome this I have created a function that converts strings to LPCWSTR types.
#ifdef _WIN32
#include "File.h"
#include <Windows.h>
std::wstring strtowstr(const std::string &str)
{
// Convert an ASCII string to a Unicode String
std::wstring wstrTo;
wchar_t *wszTo = new wchar_t[str.length() + 1];
wszTo[str.size()] = L'\0';
MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, wszTo,(int)str.length());
wstrTo = wszTo;
delete[] wszTo;
return wstrTo;
}
bool File::copyFile(std::string source, std::string destination)
{
std::wstring wsource = strtowstr(source);
std::wstring wdestination = strtowstr(destination);
int result = CopyFileW(wsource.c_str(), wdestination.c_str(), TRUE);
//for debugging...
std::wcout << "The error is " << GetLastError() <<std::endl;
std::wcout << wsource.c_str() << std::endl;
std::wcout << wdestination.c_str() << std::endl;
if (result == 0)
{
return false;
}
return true;
}
#endif
In my Test Programme
TEST(all,main_copy_file)
{
std::cout << "Testing copyFile() function..." << std::endl;
std::string srcDir = File::currentWorkingDirectory() + "srcDir";
File::makeDirectory(srcDir);
std::string destDir = File::currentWorkingDirectory() + "destDir/";
File::makeDirectory(destDir);
File::makeFile(srcDir, "testFile", ".txt");
ASSERT_TRUE(File::fileExists(srcDir + "/testFile.txt")) << "Error: Test file has not been generated" << std::endl;
ASSERT_TRUE(File::directoryExists(destDir)) << "Error: Destination directory does not exist" <<std::endl;
ASSERT_TRUE(File::copyFile(srcDir + "/testFile.txt", destDir)) << "Error: Coppy unsucsessfull" << std::endl;
ASSERT_TRUE(File::fileExists(destDir + "/testFile.txt")) << "Error: CoppyFile() flagged as sucsessfull but file does not exist" << std::endl;
}
In the application Output (on Windows)
/*
Testing copyFile() function...
The error is 5
C:\GIT\CorteX\Externals\OSAL\build\Debug/srcDir/testFile.txt
C:\GIT\CorteX\Externals\OSAL\build\Debug/destDir/
error: Value of: File::copyFile(srcDir + "/testFile.txt", destDir)
Actual: false
Expected: true
Error: Coppy unsucsessfull
*/
Error code 5 is an access denied error. I think it gives this error when either the directory does not exist, the directory is open somewhere else, or I do not have permissions.
Since I have tested that the directory does exist, I think it must be one of the latter two. I might only have restricted Admin rights (I don't know), but I can paste into the "destDir" without admin permission. So maybe it thinks the directory is open? Is there a command that exists to make sure the directory is closed?
The test is successful when running on Linux.
The CopyFile API expects file names for both source and destination files. Your code passes a directory name for the destination. This causes the API to fail. You need to append the file name for the destination as well.
Besides that, there are several other issues with your code:
The path separator on Windows is a backslash (\). Your are mixing forward slashes (/) and backslashes. Depending on the arguments passed, the system won't translate forward slashes to backslashes, before passing them on to lower-level file I/O API's.
You are calling GetLastError too late. You need to call it immediately, whenever it is documented to return a meaningful value. Do not intersperse it with any other code, however trivial it may appear to you. That code can modify and invalidate the calling thread's last error code.
Your code assumes ASCII-encoded strings. This will stop working, when dealing with files containing non-ASCII characters. This is quite common.
new wchar_t[...] buys you nothing over std::vector<wchar_t>, except the possibility to introduce bugs.
Your MultiByteToWideChar-based string conversion implementation makes (undue) assumptions about the code unit requirements of different character encodings. Those assumptions may not be true. Have the API calculate and tell you the destination buffer size, by passing 0 for cchWideChar.
Your string conversion routine ignores all return values, making bugs ever so likely, and unnecessarily hard to diagnose.
I know this is an old post, but for anyone who stumbles here needing more help:
CopyFile has the following constraints which if not met can give access denied error:
Insufficient permissions for the current user
File is in use
Filepath is a directory and not a file
File is read-only
In my case all the above were met, still I kept getting the same error. What helped me was a simple
SetFileAttributes(filePath,FILE_ATTRIBUTE_NORMAL)
Retrieving and Changing File Attributes
SetFileAttributes

Creation of RRD files with C++ on Raspberry behaves strangely

I want to use my Raspberry Pi to record temperature from a series of sensors. For this purpose I am writing a C++ program which uses librrd.
For every connected sensor I want to create a rrd with 12 rra. The following call should create my wanted rrd:
rrd_create(mNumberOfCreateParams, mCreateParams);
mNumberOfCreateParams is 17 and the content of mCreateParams is the following:
rrdcreate
28-000005fd934f.rrd
--step=300
--no-overwrite
DS:temperature:GAUGE:600:-55:125
RRA:AVERAGE:0.5:1:288
RRA:AVERAGE:0.5:3:672
RRA:AVERAGE:0.5:12:744
RRA:AVERAGE:0.5:72:1464
RRA:MAX:0.5:1:288
RRA:MAX:0.5:3:672
RRA:MAX:0.5:12:744
RRA:MAX:0.5:72:1464
RRA:MIN:0.5:1:288
RRA:MIN:0.5:3:672
RRA:MIN:0.5:12:744
RRA:MIN:0.5:72:1464
The second line changes each time corresponding to the id of the sensor.
Now the problem: Some time the call to rrd_create works as intended but at some point it stops working and just creates errors on further calls. This is even true if I want to recreate an rrd which was successfully created previously.
By changing mNumberOfCreateParams I can alter the number of parsed arguments. If the parameter is in range of 13 to 17 the error returned by rrd_get_error() is "can't parse argument ' ' " (added space between ' for readability). If I let the function parse 10 to 12 parameters it will "work" the first time and return "opening '#': No such file or directory" the second time because the first time the following file was created:
image of created file in file browser
If the number of parsed parameters is below 10 it is working as intended.
There isn't any difference if I change the order of the RRA lines.
If I call rrdtool create [...same parameters as above] from terminal everything works fine indifferent how many parameters are parsed.
In hopes of rrd_create again working I restarted the Raspberry serveral times and it even worked once for a short amount of time (one run of my application).
Are there any suggestions what I am doing wrong or how I can move rrd_create into a more stable state?
Edit:
I'm using version 1.4.7 of RRDtool (rrdtool version in shell).
Here is the code I'm using for creation of rrd files:
// mCreateParams & mNumberOfCreateParams will be set here
setupRrdCreateParamsDS18B20(lStepSize);
char lCurrentPath[255];
getcwd(lCurrentPath, sizeof(lCurrentPath));
// since I wasn't able to create rrd files outside current working directory I
// change working directory to where I want all files
chdir(DS18B20_PATH.c_str());
// the dump of mCreateParams postet above was created here
int lStatus = rrd_create(mNumberOfCreateParams, mCreateParams);
Since I dumped mCreateParams just before calling rrd_create(...) I think they shouldn't be corrupted.
My current workaround uses popen() and mCreateParams are used to create an shell command calling rrdtool.
stringstream ss;
// create shell command from create params
ss << "rrdtool create ";
for (int i = 1; i < mNumberOfCreateParams - 1; i++) {
ss << mCreateParams[i] << " ";
}
ss << mCreateParams[mNumberOfCreateParams - 1];
// needed for capturing output from executed command
FILE * in;
char buff[512];
if(!(in = popen(ss.str().c_str(), "r"))){
return false;
}
ss.str("");
ss.clear();
// get output
while(fgets(buff, sizeof(buff), in)!=NULL){
ss << buff;
}
lRrdError = ss.str();
ss.str("");
ss.clear();
int lTemp = pclose(in);
// get exit code from rrdtool create
lStatus = WEXITSTATUS(lTemp);
I am thankful for every advise.
When you call rrd_create(int argc, char**argv), you need to pass the parameters in an ARGV list, very similar to the way a normal C main() function take its parameters.
In particular, you do not need to pass the create function name (this is implicit) and, of course, the argcparameter must match the number of elements in the argv array.
So, in short: your parameter list to rrd_create should not include the rrdcreate parameter, and your argc MUST match the number of argv parameters passed.
If you still get errors returned from the rrd_create function call, then print out the error message.

C/C++ and Fortran writing to same file

I have a C/C++ library whose functions are called inside a Fortran program.
I would like to write some output generated in my library on the same file the Fortran program outputs to.
I tried to pass the filename, open it in C++, write to it and finally close it with this sample code:
std::ofstream output;
output.open(name, ofstream::out | ofstream::app);
/*
Some calculations...
*/
output << "Result is " << result << std::endl;
output.close();
Nothing is written to file, unless I remove ofstream::app but then most part of what is written by the Fortran code is destroyed...
I also tried using fprintf with a similar sample code:
FILE * pFile = fopen(name, "a");
/*
Some calculations...
*/
fprintf(pFile, "Result is = %.10E", result);
fclose(pFile);
with the same results. Any clue as to how to do this?
Even if you find a way how to do that for one set of runtime libraries, it may fail for another (e.g., different compiler collection) or another operating system... Do not do that, pass the data you want to write to the part of the system that opened the file originally.

Reading .vtk file

I'm working on VTK (Qt on ubuntu 10.04).
I'm trying to read a .vtk file having 3D image. As I could understand, this
http://www.vtk.org/Wiki/VTK/Examples/Cxx/IO/GenericDataObjectReader
makes it possible to read any vtk file. However, it does not work. All I get is :
Starting /home/taha/Downloads/VTK/Examples/qtcreator-build/GenericDataObjectReader...
Usage: /home/taha/Downloads/VTK/Examples/qtcreator-build/GenericDataObjectReader InputFilename
/home/taha/Downloads/VTK/Examples/qtcreator-build/GenericDataObjectReader exited with code 1
1) Does the code I'm using work properly? Should I change something?
Even though I know that I need to pass the filename as arguments, I may not know how to do it from command prompt. I searched on internet in detail for this but the ways I'm following might be wrong.
2) How could one pass filename as arguments to program in C++?
If you desire to call the compiled programm from the example given from vtk-wiki simply open up a shell/dos window and type:
yourExecutable.exe path-to-file.vtk
As the output stated above, you did not match the requirements for the example to run (2 parameters).
One parameter (the first) is the usage (to what program you call) and the second one containing the path to the vtk-file you want to read.
If you don't want to call it with parameters you could change the given example to this:
int main ( int argc, char *argv[] )
{
// simply set filename here (oh static joy)
std::string inputFilename = "setYourPathToVtkFileHere";
// Get all data from the file
vtkSmartPointer<vtkGenericDataObjectReader> reader =
vtkSmartPointer<vtkGenericDataObjectReader>::New();
reader->SetFileName(inputFilename.c_str());
reader->Update();
// All of the standard data types can be checked and obtained like this:
if(reader->IsFilePolyData())
{
std::cout << "output is a polydata" << std::endl;
vtkPolyData* output = reader->GetPolyDataOutput();
std::cout << "output has " << output->GetNumberOfPoints() << " points." << std::endl;
}
return EXIT_SUCCESS;
}
and simply replace setYourPathToVtkFileHere with the (preferably absolute) your path.