Mar 20, 2016 I have a directory called Lua5.2 in /usr/local/include that contains lua.h, lauxlib.h and lualib.h When I try to build the program, I get the following linker error: Davids-MacBook-Pro:sol David$ make gcc sol.o -o sol -llua -lm ld: library not found for -llua clang: error: linker command failed with exit code 1 (use -v to see invocation) make.
- Lua, Sol 3 and C (Oh, My!): Part 1 - Nice Doggy. I've seen a couple of questions now about embedding Lua in C. While it is certainly possible to use the C API in C, I wanted to introduce a pure C interface to Lua called Sol 3. Sol3 is a template based approach to Lua.
- You’ll need to #include sol/sol.hpp somewhere in your code. Sol is header-only, so you don’t need to compile anything. However, Lua must be compiled and available. See the getting started tutorial for more details. The implementation for assert.hpp with cassert looks like so.
Lua, Sol 3 and C++ (Oh, My!) : Part 1 - Nice Doggy.
I've seen a couple of questions now about embedding Lua in C++. While it is certainly possible to use the C API in C++, I wanted to introduce a pure C++ interface to Lua called Sol 3. Sol3 is a template based approach to Lua. It is extremely fast and has some very slick features for interfacing with Lua that almost completely eliminates the need to access the Lua stack.
Now, lets be very clear: I suck at C++. I think it's an abysmal language and it's practitioners are masochists. Every time I try and interface C++ with Lua I am struck by the complete dissimilarities. One is a large, complex monster ready to eat your children and destroy months of your life; the other a wonderful tool for usefully automating the world. If you read this 'article' (rant?) let the curse that is C++ be on your head, I wash my hands. Now for the foolhardy, let us have a look.
Toolchains
Sol 3 works with G++ (GNU C++ compiler) and Microsoft Visual C++ (e.g. Visual Studio 'proper'), but I will be using my WinLua Toolchain (LLVM/CLang) on Windows 10 with VS Code (not Visual Studio 'proper'). WinLua Toolchain is installed via MSI and consists of Lua 5.3, Lua Rocks (package manager), a compiler and the most sublime build system: xmake. While I am eager to announce WinLua, it's still not quite ready. Feel free to download and follow along, but the debugger doesn't work in VS Code (GDB command line only!) and LuaRocks is a little finky. The MSI uninstaller completely removes it from your system, so using it is relatively risk free. None the less, there should be a full WinLua release before the end of the year.
While build systems are plentiful, I will rely on xmake for this article. If you wish to use xmake without Winlua (e.g. with VC++ or Mingw-64), download instructions are here.
Sol 3
Sol 3 is a 'Header Only' Lua interface (5.1+) to C++ written against the C++ 17 standard. Header Only, means you don't have to build a library, or add source trees. C++17 is important because it takes advantage of all the latest tools and compiler tricks to make your Lua calls lightening fast. To use Sol 3 you just include the header in your C++ application and you're done. That simple! There are some parts that are pure magic and completely obfuscate the boundaries between C++ and Lua. However, Sol3 is, a tricky beast due to it being C++17 and primarily written in C++ templates and there are decisions and design tradeoffs that will need to be made later in your projects. Most of that difficulty, however, is outside the scope of this article.
The documentation for Sol 3 is quite extensive and the tutorials/examples are plentiful. Getting started is relatively easy. However, even after spending time with the tutorials, I often found myself asking 'ya, but I just want to...', 'sure, but what if I need to...' and so forth. That was true until I started to understand the brilliant use of generics to make accessing Lua very simple. Unfortunately the API reference is dense C++ templates written for those who are already initiated. Remember, this is C++ and you are supposed to know what you're doing. None the less, I hope to spell out some of those rough spots.
Finally, a note about where to find help. While I can provide some information, I am only a few steps ahead of you in my use of Sol 3 (remember, I don't like C++). The Sol 3 maintainer/author is amazing and should be your go-to source for issues. The Phantom Derpstorm - aka ThePHD - has always answered my github questions very quickly and provided the necessary - albeit densely technical - solutions. And no, ThePHD is not a doctor (yet? I embarrassed myself on the lua-l mailing list once).
So, without further ado, lets get started.
Pre-Requisites
- Lua 5.3+
- C++ Compiler and build tools
- Sol header file
- IDE, preferably a debugger
- (optional) Command line shell (powershell, terminal, WSL, gitbash, msys2, etc.)
If you already have Lua and a compiler toolchain set up, then download the Sol 3 git repository and copy the 'single' hpp file to your include directory:
(Note the repository is still called sol2. Officially Sol 3 is called Sol 2 v3. <head explodes>)
If you've decided you want to follow along with WinLua, then download WinLua Toolchain, and run the installer. Sol 3 comes packaged with Winlua so it is already installed.
WinLua Setup in VS Code
Next, download and open Visual Studio Code and install two add ins: xmake and C++.
First, C++...
Next, the xmake plugin
If you clear your search box, you will see the two installed plugins:
You can now set up a folder for your project. Once you've created your containing folder (in my case, thats LuaSolExample), I need to create some subfolders and an empty file for Sol. We need to create includesolconfig.hpp by right clicking, creating the include folder, then double click into the include folder, then creating the sol folder. Finally, in the sole folder, right click and create a 'new text file' and rename the file config.hpp. *NOTE: If you have file extensions hidden in Windows Explorer, you will need to show extensions (menu bar -> view -> check File name extentions) and remove the '.txt' at the end.* Create a folder, then right click in the folder and select 'open in VSCode'.
With this part complete, there are only one or two more 'WinLua specific steps for VS Code', but for now, lets move on to some generic code.
Hello World
In you editor of choice, create a file called main.cpp and enter the following contents:
This code is almost directly from the Sol 3 tutorials. As you can see, getting started is amazingly simple. With three lines of code, we can get Lua to say something for us.
As with any C or C++ program, there are two things that need to be specified in order to complete our application:
1) We need to tell a compiler where to find the header files included in our project and
2) We need to tell the linker where to find the binaries that contain the functionality that we want to include in our application.
In our case, we need the compiler to know where the sol.hpp file and the config.hpp files are located, as well as the header files for Lua. While you can see that we have not included any Lua headers in our application, the Sol 3 library links to Lua for us, so we need to specify them too.
As for the binary libraries that actually contain the functionality, we are lucky in that only a Lua library is required because Sol 3 is a header only implementation. Note that if you are using WinLua or Microsoft VC++ (`cl`), you will need to have a *.lib file for Lua. That file can be a static lib or a linking lib, but you need that file. A lua53.dll file will not work by itself. If you are using GNU g++, you are exempt (`ld` will link directly to a DLL. yikes!).
Now, if you are using Visual Studio VC++, you will need to drill into endless dialog boxes and specify the correct settings. I will not specify the VS configuration here, but if someone asks in the comments, I will perhaps relent.
Building Our Example
While one could use Visual Studio (msbuild from the command line), WinLua provides three possible build systems: the veritable GNU `make` ('gmake'), the sublime lua based `xmake`, and `luarocks`. GNU `make` is excellent if you have a long grey unix beard or you are particularly keen on slamming your head against hard objects. Luarocks is excellent if you are creating Lua modules only. Since neither of these scenarios applies directly to this article, we will skip to xmake (And in case my bias wasn't obvious enough - because it's my favorite and I am the one writing this article, so there).
Open powershell and `cd` into your directory. I use Windows Terminal from the Windows store:
Xmake is excellent at detecting existing toolchains. If VC++ is installed, it will find that first.
If GNU mingw-64 is available in the path, it will find that (if VC++ isn't present). For our example, I am going to set a global mingw directory and specify the project configuration parameters:
The following table explains the switches:
Value | |
f | Specified 'config' to configure the project |
N/A | |
-v | verbose |
i686 | Architecuture - i386 or i686 can be specified for 32 Bit. x86_64 is the 64 bit designation. WinLua is only 32 bit at the moment so we will use i686. WinLua 64 bit is not far off. |
mingw | Platform: Mingw is the C/C++ library we will be using. |
debug | Compilation 'mode'. Also known as a build configuraiton. |
xmake will also generate a new xmake.lua file for you. If we try it however, it will fail because we haven't specified our headers or link libraries:
Let's pop open VS Code again and update our xmake.lua file
Our xmake file specifies a 'target', being the thing we are going to build. Within that target it sets the kind of build and adds our C++ file. However, what it does not do yet is define where our header files are, or where our link libraries are. Lets add that now:
We have added three lines that tell the compiler and linker where to find the pieces they need to complete the program. I have used the include directory for WinLua because Sol and all the Lua files are in there. I have also added our own include directory so that the system can find sol/config.hpp. If you put Sol 3 in your own include directory, your includes would like something like this:
Now lets try again from the command line:
Ooops. That didn't go well. What happened? I left this error in here because it's an important one to know about. This error is telling you in a round about way that you are using the wrong C++ standard. Remember, Sol 3 uses C++17. Most compilers default to C++11 or C++14. Let's fix that using a compiler option in our xmake.lua file:
Save the file, drop back to the command line, and lets try again. (Note that `xmake`, `xmake build` and `xmake b` all run the build command):
OH MY GOD! It worked, it worked, it worked it...(dance of joy). Ahem. I mean: As you can see, we have now compiled our first Lua/C++ application. Let's try running it:
Conclusion
In this article I have very, very, very briefly outlined how to link Lua to C++ using the Sol 3 Lua bindings. If you want to charge ahead, there are plenty of samples in the Sol 3 documentation and in the repository. Next week(ish), I will post the second part of the article outlining a simple use of Sol 3. If you are familiar with Lua's stack based access, the simplicity of Sol 3 will blow your mind. If you've not had the 'pleasure' of accessing Lua from C, then Sol 3 is going to spoil you. Either way, I think you'll appreciate the masterpiece that will shed light on Lua/C++ (Sol means sun in portugese. 'shed light', sun... get it?)
Dinsdale
Apr 14th, 2019
Never
Sol 3.2 — Sol 3.2.3 Documentation
Not a member of Pastebin yet?Sign Up, it unlocks many cool features!
- struct a
- a(sol::this_state ts, sol::this_environment te)
- lua_State* L = ts;
- }
- sol::object get_property_lua(const char* name, sol::this_state s)
- }
- void set_property_lua(const char* name, sol::stack_object object)
- std::cout << 'SET PROPERTY: ' << name << std::endl;
- }
- std::unordered_map<std::string, sol::object> props;
- };
- struct nofun
- nofun()
- };
- struct b : public a, public nofun
- b(sol::this_state ts, sol::this_environment te, int ab ) : a(ts, te)
- std::cout << 'IM ALIVE!' << std::endl;
- lua.script('function break_crap(b_obj) b_obj.test3 = {} end');
- sol::protected_function pf = lua['break_crap'];
- if (!result.valid()) {
- }
- b(sol::this_state ts, sol::this_environment te, int ab, int bc ) : a(ts, te)
- ~b()
- std::cout << 'IM MELTING..' << std::endl;
- };
- struct c : public b
- c(sol::this_state ts, sol::this_environment te, int ab) : b(ts, te, ab)
- std::cout << 'IM ALIVE!' << std::endl;
- c(sol::this_state ts, sol::this_environment te, int ab, int bc) : b(ts, te, ab, bc)
- ~c()
- std::cout << 'IM MELTING..' << std::endl;
- };
- void lua_test()
- sol::lib::os,
- sol::lib::math,
- sol::lib::package,
- sol::meta_function::new_index,
- sol::meta_function::index,
- );
- lua.new_usertype<b>('b',
- sol::constructors<b(sol::this_state, sol::this_environment, int),
- b(sol::this_state, sol::this_environment, int, int)>(),
- &b::set_property_lua,
- &b::get_property_lua,
- sol::bases<a, nofun>()
- lua.new_usertype<c>('c',
- sol::constructors<c(sol::this_state, sol::this_environment, int),
- c(sol::this_state, sol::this_environment, int, int)>(),
- &c::set_property_lua,
- &c::get_property_lua,
- sol::bases<b>()
- lua.script(R'(
- init_entity_properties(e)
- end
- function init_entity_properties(e)
- e._internal_entity_properties_ = {}
- function e : GetName()
- end
- function e : SetName(s)
- self._internal_entity_properties_['name'] = s
- --return e
- //sol::environment current_env = lua.globals();
- //sol::environment tmp = sol::environment(lua, sol::create, lua.globals()); // make an env
- lua.script('b_tmp = b.new(1)'); // instantite an obj..
- a * b_base = lua['b_tmp']; // get the base...
- sol::protected_function pf = lua['init_entity'];
- if (!result.valid()) {
- }
- //lua['b_base'] = b_base; // jam the parent ref into lua
- //ua.script('b_base.test = nil'); // this should work
- //lua.script('b_tmp.test2 = nil'); // this should fail
- lua.script('c_tmp = c.new(1)'); // instantite an obj..
- // lua.script('d1 = nil', tmp); // destroy or new baby
- }
RAW Paste Data