I've created a cpp file with the main method implementing calls to lua.
When compiling + executing the qt project I receive the following error:
PANIC: unprotected error in call to Lua API (attempt to call a string value)
The problem is that lua cannot find the lua file to be executed (at least I think it is). So I copied the file to all the debug dirs and the main dir but it still didn't work.
Thanks for helping me!
main.cpp
#include <stdio.h>
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
lua_State* L;
int main(int argc, char *argv[])
{
/* initialize Lua */
L = luaL_newstate();
/* load Lua base libraries */
luaL_openlibs(L);
/* load the script */
luaL_loadfile(L, "test.lua");
lua_call(L, 0, 0);
/* cleanup Lua */
lua_close(L);
}
and the file test.lua
-- test
print("Hello World")
Given that this is a run-time file operation, the function is likely only looking in the current directory.
It seems like Qt uses the user's directory as default path.
You can validate this with: (thanks Rich)
QDir dir(".");
qDebug() << dir.absolutePath();
When putting the lua script into this folder everything works like a charm.
The working directory can be set with the following command:
QDir::setCurrent()
And in combination with
QCoreApplication::applicationFilePath()
The path can be set to where the exe resigns in.
This is not really related to Qt since you are not using any of the Qt API in your software.
You should check the status returned by the lual_loadfile method like shown in this example. That should give you some additional clues about what is going wrong.
Just in case, there's a QtLua module that could be of interest.
Related
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?
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.
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.
I'm using VS2015 in a C++ application with Lua5.1. I'm running a very simple Lua script with no issue, raw lua works fine. but when I attempt to import a lua module "socket.http" my application doesn't like it because I imagine it can't find the module.
My question is how do I allow my lua script (being run from c++) to access lua modules like socket.http?
My project.cpp
#include "stdafx.h"
#include <iostream>
extern "C"
{
#include <../dependancies/lua51/include/lua.h>
#include <../dependancies/lua51/include/lauxlib.h>
#include <../dependancies/lua51/include/lualib.h>
}
void report_errors(lua_State *L, int status)
{
if (status != 0)
{
printf("-- %s\n", lua_tostring(L, -1));
lua_pop(L, 1); // remove error message
}
}
int main()
{
// create a Lua state
lua_State* L = luaL_newstate();
// load standard libs
luaL_openlibs(L);
int lscript = luaL_dofile(L, "test1.lua");
report_errors(L, lscript);
system("PAUSE");
return 0;
}
test1.lua
local http = require("socket.http")
errors
module 'socket.http' not found:
no field package.preload['socket.http']
no file '.\socket\http.lua'
no file 'C:\Users\georg\Desktop\git\ARGO\Game\ATracknophilia\Debug\lua\socket\http.lua'
no file 'C:\Users\georg\Desktop\git\ARGO\Game\ATracknophilia\Debug\lua\socket\http\init.lua'
no file 'C:\Users\georg\Desktop\git\ARGO\Game\ATracknophilia\Debug\socket\http.lua'
no file 'C:\Users\georg\Desktop\git\ARGO\Game\ATracknophilia\Debug\socket\http\init.lua'
no file 'C:\Program Files (x86)\Lua\5.1\lua\socket\http.luac'
no file '.\socket\http.dll'
no file '.\socket\http51.dll'
no file 'C:\Users\georg\Desktop\git\ARGO\Game\ATracknophilia\Debug\socket\http.dll'
no file 'C:\Users\georg\Desktop\git\ARGO\Game\ATracknophilia\Debug\socket\http51.dll'
no file 'C:\Users\georg\Desktop\git\ARGO\Game\ATracknophilia\Debug\clibs\socket\http.dll'
no file 'C:\Users\georg\Desktop\git\ARGO\Game\ATracknophilia\Debug\clibs\socket\http51.dll'
no file 'C:\Users\georg\Desktop\git\ARGO\Game\ATracknophilia\Debug\loadall.dll'
no file 'C:\Users\georg\Desktop\git\ARGO\Game\ATracknophilia\Debug\clibs\loadall.dll'
no file '.\socket.dll'
no file '.\socket51.dll'
no file 'C:\Users\georg\Desktop\git\ARGO\Game\ATracknophilia\Debug\socket.dll'
no file 'C:\Users\georg\Desktop\git\ARGO\Game\ATracknophilia\Debug\socket51.dll'
no file 'C:\Users\georg\Desktop\git\ARGO\Game\ATracknophilia\Debug\clibs\socket.dll'
no file 'C:\Users\georg\Desktop\git\ARGO\Game\ATracknophilia\Debug\clibs\socket51.dll'
no file 'C:\Users\georg\Desktop\git\ARGO\Game\ATracknophilia\Debug\loadall.dll'
no file 'C:\Users\georg\Desktop\git\ARGO\Game\ATracknophilia\Debug\clibs\loadall.dll'
Rules for modules is the same, no matter if you had script started from c++ or from a Lua command line interpreter.
You must have that module in the path where Lua searchers/loaders will try to find it. See the list of paths searched, put that http dll (compiled with same settings as your project, in case Lua is linked statically) in one of searched paths.
And you have to distribute that module along with your program, don't expect it to be installed on user's pc.
I have downloaded pdcurses source and was able to successfully include curses.h in my project, linked the pre-compiled library and all good.
After few hours of trying out the library, I saw the tuidemo.c in the demos folder, compiled it into an executable and brilliant! exactly what I needed for my project.
Now the problem is that it's a C code, and I am working on a C++ project in VS c++ 2008.
The files I need are tui.c and tui.h
How can I include that C file in my C++ code? I saw few suggestions here
but the compiler was not too happy with 100's of warnings and errors.
How can I go on including/using that TUI pdcurses includes!?
Thanks
EDIT:
I added extern "C" statement, so my test looks like this now, but I'm getting some other type of error
#include <stdio.h>
#include <stdlib.h>
using namespace std;
extern "C" {
#include <tui.h>
}
void sub0()
{
//do nothing
}
void sub1()
{
//do nothing
}
int main (int argc, char * const argv[]) {
menu MainMenu[] =
{
{ "Asub", sub0, "Go inside first submenu" },
{ "Bsub", sub1, "Go inside second submenu" },
{ "", (FUNC)0, "" } /* always add this as the last item! */
};
startmenu(MainMenu, "TUI - 'textual user interface' demonstration program");
return 0;
}
Although it is compiling successfully, it is throwing an Error at runtime, which suggests a bad pointer:
0xC0000005: Access violation reading location 0x021c52f9
at line
startmenu(MainMenu, "TUI - 'textual user interface' demonstration program");
Not sure where to go from here.
thanks again.
If I'm not mistaken (and I could easily be), it's due to the difference in calling conventions for C/C++. Try making the callbacks extern "C", and make them call a C++ function. Call it a trampoline :)
Finally got it working. The solution was in the steps below:
First I renamed tui.c to tui.cpp
For the header tui.h, I followed the exact same step of wrapping the code as described here.
then in my project i just included the header without any extern "C" block
#include "tui.h"
Compiled and it worked!
I create a simple test.cpp file in my Xcode project.
#include "MyTest.h"
#include <stdio.h>
int main(int argc, char** argv) {
printf ("Calling MyTest Main\n");
}
It compiles. I think I need to create a Target and Executables before I can launch in XCode.
But I need some help with these questions:
1. What kind of Target i should create for my simple .cpp file? It is not a GUI application.
2. How to specify this main in test.cpp to be the starting point of my Target and Executable?
Thank you.
1) You probably want a Command Line Tool application.
2) When you launch your tool, the mach kernel calls the start() function in the C Runtime Library, which invokes main() with the count of arguments (argc) and an array of argument string pointers (argv). So the main() that you show above is what will run.
You can use a special linker command to designate one of your own functions to be run instead of start(), but almost nobody does.
For example: I'm on MS DOS, I have a source code in the folder C:\Documents and Settings\Programs. Can i make my source code use a program (for example gnuplot) that is in a random folder?
http://www.codeproject.com/KB/system/newbiespawn.aspx
ShellExecute will look into the PATH environment variable, so you don't need to specify the full PATH. Now, if it's really a random location and it's not even in the PATH environment variable, then I guess you are out of luck.
If they aren't even in the PATH, then you have to search for it in the candidates folder. Here's sample code on how to traverse a file system path in C++.
And an example using Boost:
directoryList.h
#ifndef DIRECTORYLIST_H_INCLUDED
#define DIRECTORYLIST_H_INCLUDED
#define BOOST_FILESYSTEM_NO_DEPRECATED
#include <iostream>
#include <list>
#include <string>
class directoryList {
public:
directoryList();
~directoryList();
std::list<std::string> getListing(std::string path);
};
#endif // DIRECTORYLIST_H_INCLUDED
directoryList.cpp
#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/convenience.hpp"
#include "boost/filesystem/path.hpp"
#include "boost/progress.hpp"
#include "directoryList.h"
using namespace std;
namespace fs = boost::filesystem;
directoryList::directoryList() {}
directoryList::~directoryList() {}
list<string> directoryList::getListing(string base_dir) {
list<string> rv;
fs::path p(base_dir);
for (fs::recursive_directory_iterator it(p);
it != fs::recursive_directory_iterator(); ++it) {
string complete_filename = it->path().string();
rv.insert(rv.begin(),complete_filename);
}
return rv;
}
Usage sample:
directoryList *dl = new directoryList();
filenames = dl->getListing("C:\\Program Files");
//search for the file here, or modify the getListing to supply a filter
Here are some options:
Search in the system PATH for the executable you want to run
Allow the user to specify the location on the command-line
Store the location in a configuration file, and allow the user to specify it during install (if you have an install process) or by editing the file by hand
Ideally you'd do all 3
Also there are some core functions _exec/exec and its modifications. Similar functions are available for Linux.
The location of source code has nothing to do with the way programs are located by system() call (I assume you use that call). The only relevant consideration is the location of the compiled executable.
Please take a look at PATH environment variable in Windows - this is how programs are found. It's a semicolon-separated list of directories where Windows looks for executables and BAT files and DLLs. To that list, current directory and (I think) the place where your EXE is are prepended.
The PATH is set in Windows XP from System control panel widget Advanced tab Environment button. For Vista, things are more complicated - you need to do it as administrator.
As Vinko said, the PATH environment variable determines where Windows will look for program files.
It's usually best to avoid hard-coding the path of an executable into your compiled program. Even if gnuplot is in a particular folder on your machine then it might well not be in the same folder on someone else's computer. This would cause your call to the other program to fail. You could store it in the registry and let the user configure the program location, or provide an installer that searched for it.