Skip to content

Instantly share code, notes, and snippets.

@caiorss
Created June 16, 2020 21:18
Show Gist options
  • Save caiorss/17a37d905d3d71c0ae66661a189481b5 to your computer and use it in GitHub Desktop.
Save caiorss/17a37d905d3d71c0ae66661a189481b5 to your computer and use it in GitHub Desktop.
Embed Lua engine in a C++ app
cmake_minimum_required(VERSION 3.0)
project(lua-sol-embed)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_VERBOSE_MAKEFILE ON)
include(lua-lib.cmake)
#----- Target Definitions ----------------------------#
add_executable( embed-lua-sol embed-lua-sol.cpp)
target_link_libraries( embed-lua-sol lua::lualib )
# Lua REPL executable built from static library liblua.a (Linux)
# Note: the main() function is in the file main.c in the lua sources directory
add_executable( lua-repl $<TARGET_OBJECTS:lua::lualib> )
target_link_libraries( lua-repl m pthread )
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <sol/sol.hpp>
class Counter {
private:
std::string m_name;
int m_counter;
public:
// Ctor [1] => Default ctor
Counter(): Counter("untitled", 0) { }
// Ctor [2]
Counter(std::string name, int counter)
: m_name{std::move(name)}, m_counter{counter}
{
std::cout << " [TRACE] Counter created with => { "
<< " name = " << m_name
<< " ; counter = " << m_counter
<< " } \n";
}
int getCounter() const { return m_counter; }
void setCounter(int n) {
m_counter = n;
std::cout << " [TRACE] I was set to value " << n << std::endl;
}
void increment() {
m_counter++;
std::cout << " [TRACE] increment event =>> counter = { "
<< m_name << " ; " << m_counter
<< " } " << std::endl;
}
};
double add_fun(double a, double b)
{
std::cout << " [TRACE] addfun() => a = " << a
<< " ; b = " << b << std::endl;
return a + b;
}
void sol_eval(sol::state& ctx, std::string code)
{
try {
ctx.script( std::move(code) );
} catch ( sol::error const& ex) {
std::cerr << " [SOL ERROR] " << ex.what() << "\n";
}
}
int main()
{
// Create an instance of lua Engine (aka virtual Machine)
sol::state ctx{};
// Load basic libraries (such as print)
ctx.open_libraries(sol::lib::base, sol::lib::coroutine, sol::lib::string, sol::lib::io);
// Register function pointer
ctx.set_function("add_fun", &add_fun);
// Register lambda object
ctx.set_function("make_vector", [](int n ) -> std::vector<int> {
auto vec = std::vector<int>(n);
for(int i = 0; i < n; i++ ) vec[i]= i * 3;
return vec;
});
// Set variables in the Lua engine
ctx["points"] = 2000;
ctx.set("character", "<Marcus Tulius Cicero>");
/* ===========>>> E X P E R I M E N T / 1 <<=========*/
std::puts("\n [EXPERIMENT 1] ==>> Evaluating string as code ");
{
// ===>>> Eval code as string <<===
// Throws exception sol::error
ctx.script(R"(
print(" [LUA] Hello world lua ");
x = add_fun(10, 20);
print("\n [LUA] result = " .. x);
v = make_vector(5);
print("\n [LUA] Printing a vector ");
for i = 1, 5 do
print(" -> v[" .. i .. " ] = " .. v[i] );
end
print(" [LUA] VAR points = " .. points );
print(" [LUA] VAR character = " .. character );
)");
}
/* ===========>>> E X P E R I M E N T / 2 <<=========*/
std::puts("\n\n [EXPERIMENT 2] ==>> Reading configuration ");
{
ctx.script(R"(
-- Simulation of user configuration from script
asset_path = "C:\\\\Users\\myuser\\data\\files\\";
user_credits = 2000;
width = 200.561;
)");
auto asset_path = ctx.get<std::string>("asset_path");
int user_credits = ctx["user_credits"];
std::cout << " [*] => asset_path = " << asset_path << "\n";
std::cout << " [*] => user_credits = " << user_credits << "\n";
}
/* ===========>>> E X P E R I M E N T / 3 <<=========*/
std::puts("\n\n [EXPERIMENT 3] ==>> Register C++ classes ");
struct StatefulFunctor {
int state = 0;
StatefulFunctor(int state): state(state){ }
int operator()(){
std::cout << " *=>> [StatefulFunctor] My new state is = "
<< this->state << "\n";
return state++;
}
};
auto stateful = StatefulFunctor(10);
ctx.set_function("stateful", stateful);
ctx.script(R"(
stateful();
stateful();
stateful();
)");
ctx.new_usertype<Counter>(
// Class name
"Counter"
// --- Register methods ------ //
,"getCounter", &Counter::getCounter
,"setCounter", &Counter::setCounter
,"increment", &Counter::increment
// --- Register properties ---- //
, "value", sol::property( &Counter::getCounter
, &Counter::setCounter)
);
sol_eval(ctx, R"(
print("\n ----->>> Calling C++ classes from Lua <----- ");
-- Create new instance (object) of C++ class Counter
counter = Counter.new();
counter:increment();
counter:increment();
counter:increment();
x = counter:getCounter();
print(" [*] value of counter is equal to = " .. x);
counter.value = 2000;
print(" [*] Counter value is equal to = " .. counter.value );
)");
Counter* ptr = ctx.get<Counter*>("counter");
std::cout << " [FROM C++] counter value = "
<< ptr->getCounter()
<< "\n";
return 0;
}
include(FetchContent)
# Note: the 'add_subriectory' line was commented becuyase
# library that will be downloaded does not have
# a CMakeListst.txt file at the root directory.
macro(Download_Library_Git NAME TAG REPOSITORY_URL)
FetchContent_Declare(
${NAME}
GIT_REPOSITORY ${REPOSITORY_URL}
GIT_TAG ${TAG}
)
FetchContent_GetProperties(${NAME})
if(NOT cpputest_POPULATED)
FetchContent_Populate(${NAME})
message("${NAME}_SOURCE_DIR} = ${${NAME}_SOURCE_DIR}")
# => Disable following line: the library does not have a CMakeLists.txt
# at the root directory.
# add_subdirectory(${${NAME}_SOURCE_DIR} ${${NAME}_BINARY_DIR})
endif()
endmacro()
# ====>> Download Lua library <<==========================#
Download_Library_Git( lua
v5.3.5
https://github.com/lua/lua
)
file(GLOB_RECURSE lua_sources "${lua_SOURCE_DIR}/*.c")
file(GLOB_RECURSE lua_headers" ${lua_SOURCE_DIR}/*.h")
message( [TRACE] " lua_SOURCE_DIR = ${lua_SOURCE_DIR} ")
add_library( lua STATIC ${lua_sources} ${lua_headers} )
target_include_directories( lua PUBLIC ${lua_SOURCE_DIR} )
add_library( lua::lualib ALIAS lua)
# ====>> Download Sol C++ binding library <<====================#
FetchContent_Declare( sol2
GIT_REPOSITORY https://github.com/ThePhD/sol2
GIT_TAG v3.2.0
)
FetchContent_MakeAvailable( sol2 )
include_directories( ${sol2_SOURCE_DIR}/include )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment