PeterMemo

主にC++,OpenGL,Siv3Dのプログラミング関連の内容です.

LuaとSolをC++から使う(導入、入門)

LuaとSolをc++で使う方法を紹介します。(OSはWindows)
細かいことはいいからとにかく使いたいって人向けです。一応c言語をざっくり理解してる体で書きます。

Luaとは
スクリプト言語だけど速いです。

・Solとは
Luac++で使うための何かです。

【導入方法】
Lua
とりあえず公式サイトに行ってください
Lua Binaries Download
そうしたら、Windows64bitの人は"lua-5.3.4_Win64_dllw4_lib.zip"をダウンロードしてください。2018/1/25現在では5.3.4が最新でしたが、これより新しいのがあったらそちらを落としてください。
f:id:peterpanppp:20180125181923p:plain

てきとうな場所で展開したあと、いい感じの場所に移動させておきます。ぼくの場合は"C:\Program Files (x86)\lua"にincludeフォルダ、liblua53.a、lua53.dllを入れておきました。(C:\Program Files (x86)にluaというフォルダを自分で作りました。)

それではテストプログラムを動かしてみます。

まずは普通のVisual C++Windowsコンソールアプリケーションのプロジェクトを作成します。

ここからがちょっとだけ重要です。

やることは4つあります。

1つ目
上のほうにあるプロジェクト(P)からプロパティを開きます。
C/C++の全般の追加のインクルードディレクトリに、さっき展開した中身のincludeフォルダのパスを追加します。ぼくの場合はC:\Program Files (x86)\lua\includeです。

2つ目
リンカーの追加のライブラリディレクトリに、libを入れてあるフォルダのパスを追加します。ぼくの場合はC:\Program Files (x86)\luaです。

3つ目
リンカーの入力に、liblua53.aを追加します。

4つ目
このプロジェクトのexeとかが置かれている場所かcppファイルが置かれている場所(ワークスペース?)にlua53.dllを置いておきます。自身がなかったらとりあえずいろんなところに置いておきましょう笑

これで動くようになったと思います。こんな感じの作業はluaに限らずライブラリとかを使う時にはよくやるのでなんとなく覚えておくといいかもです。
それではサンプルを動かしてみましょう。

#include "stdafx.h"
#include <lua.hpp>

int _tmain(int argc, _TCHAR* argv[])
{
    lua_State *L = luaL_newstate();
    lua_close(L);

    return 0;
}

警告 LNK4272 ライブラリのコンピューターの種類 'x64' がターゲットのコンピューターの種類' x86' と競合しています

こんな感じのエラーがでたら、たぶんダウンロードするときに64と32を間違えたか、ソリューションプラットホームをx86のまま動かしていると思うので、前者ならダウンロードし直し、後者ならx64に変更して再トライしましょう。この記事書いてて思いましたがx64用なのにProgram Files (x86)にフォルダ作ったのおかしいですね笑
f:id:peterpanppp:20180125185232p:plain

エラーが出なければオッケーです。

・Sol
ここにいってsol.hppをダウンロードしましょう。
Releases · ThePhD/sol2 · GitHub
そしたら、sol.hppをプロジェクトのcppとかがある場所にコピペして、既存の項目の追加で追加しましょう。

これで準備ができました。サンプルを動かしてみます。

#include "stdafx.h"
#include <lua.hpp>
#include "sol.hpp"

int _tmain(int argc, _TCHAR* argv[])
{
	sol::state lua;
	lua.open_libraries(sol::lib::base, sol::lib::package);
	lua.script("print('Hello Work')");
	lua_State *L = luaL_newstate();
	lua_close(L);
	return 0;
}

たぶんうまくいくと思います。

【サンプル】
最後にサンプルと簡単な解説をしていきます。
まずはcppの方から

#include "stdafx.h"
#include <lua.hpp>
#include "sol.hpp"
#include<iostream>

int main()
{
	sol::state lua;
	lua.open_libraries(sol::lib::base, sol::lib::package);
	lua.script("print('Hello Work')");
	lua.script_file("test.lua");
	std::cout << lua["a"].get<int>();
	std::cout << lua["b"].get<int>();
	std::cout << lua["c"].get<int>() << std::endl;
	std::cout << lua["not_exist"].get_or(999) << std::endl;
	ret = lua["f"](20);
	std::cout << ret << std::endl;
	int ret = lua["f2"](100,200);
	std::cout << ret << std::endl;
	ret = lua["f3"]();
	std::cout << ret << std::endl;
	auto it = lua["f4"]();
}

次はlua。ちなみに.luaファイルは普通に.txtファイルの拡張子を.luaに変えればできると思います。
test.lua

a = 114
b = 514
c = 1919810
local classA = {
  value = 0,
  get = function( self )
     return self.value
  end,
  set = function( self, value )
     self.value = value--コメントアウト
  end,
  update=function(self,val)
  	 self.value=val+self.value
     return self.value
  end,	
}	

function f(x) 
	return x * 3 end

function f2(x,y)
	return x+y end
	
function f3()
	return a end
	
function f4()
	print("PeterPan")
	print( classA:get() ) 
	classA.set( classA, 1 )
	print( classA.get( classA ) )
	print(classA.set(classA,0))
	print("---------------------")
	for v = 0, 100 do
		if v%10==0 then
			print( classA.update( classA,v ) ) 
		end
	end
	print("---------------------")
	classA.set(classA,1000)
	print( classA.update( classA,555 ) )
	return end

軽い解説します。ほんとに軽いです。
まずはcpp側のこれ。

sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::package);

おまじないです。ぼくもとりあえず動けばいいというスタンスなので現時点では何か知りません。そのうちしっかり理解しようと思います。

lua.script("print('Hello Work')");

これはたぶんprint('Hello Work')と書かれている.luaファイルを読み込んで実行しているのと同じ状況になるんだと思います。lua.script("print(10+100+1)");にしたら111って表示されます。

ここから.luaが関わってきます。
cpp

lua.script_file("test.lua");
std::cout << lua["a"].get<int>();
std::cout << lua["b"].get<int>();
std::cout << lua["c"].get<int>() << std::endl;
std::cout << lua["not_exist"].get_or(999) << std::endl;

ここではtest.luaを読み込んで、lua側に書かれている変数a,b,cの値をint型として取得しています。最後の行はもしlua側にnot_existという変数がなかったら999ということにしておくって感じです。

lua

a = 114
b = 514
c = 1919810

lua側は上からプログラムが動くというわけではないので、構文だけ守っててきとうに書きなぐればオッケーです。

cpp

int ret = lua["f2"](100,200);
std::cout << ret << std::endl;
ret = lua["f3"]();
std::cout << ret << std::endl;

lua

function f(x) 
	return x * 3 end

function f2(x,y)
	return x+y end
	
function f3()
	return a end

簡単な関数を用意して動かしています。こんな感じで書くんですね。最後のreturn aのaはさっき定義した114が入っているやつです。あれグローバル変数なんですね。

最後にいろいろ詰め込んだ関数です。
cpp

auto it = lua["f4"]();

lua

local classA = {
  value = 0,
  get = function( self )
     return self.value
  end,
  set = function( self, value )
     self.value = value--コメントアウト
  end,
  update=function(self,val)
  	 self.value=val+self.value
     return self.value
  end,	
}

function f4()
	print("PeterPan")
	print( classA:get() )
	classA.set( classA, 1 )
	print( classA.get( classA ) )
	print(classA.set(classA,0))
	print("---------------------")
	for v = 0, 100 do
		if v%10==0 then
			print( classA.update( classA,v ) ) 
		end
	end
	print("---------------------")
	classA.set(classA,1000)
	print( classA.update( classA,555 ) )
	return 
end

ここではclassAというクラスを作ってみました。
メソッドはこんな感じで書けばいいんですね。luaではコメントアウトは--らしいです。
for文は

for v = 0, 100 do
	--なんか処理
end

こんな感じで書くと0から100まで1ずつ増えていくやつができます。注意することは、0から99ではなく、100まで進むこと、カウンタを+1以外にするにはfor i = 0, 100, 2って書くってことです。

if文は

if v%10==0 then
    --なんか処理
end

こんな感じで書きます。他の制御文もc言語がわかればなんとなく察することができそうです。あと、たぶんですけどi=i+1を意味する、i++とかi+=1は使えないと思います。

【最後に】
最後まで見てくれてありがとうございます。ここではほんとに触りの触り程度にしか説明をしていません。さらに踏み込んだ内容は自力で頑張って見てください。また、この記事は
qiita.com
qiita.com
これらの記事を参考に書きました。リンク先の記事の方はもっと詳しいことまで書いてあるので良ければ参考にしてみるといいかもです。
luaを始めてから2日くらいですが、正直何に使えばいいのかまだ見えてきません。現段階では、細かいパラメータをluaで管理すれば、ちょっと変更を加えたとしてもコンパイルしなおす手間がない、Pythonでも使えるらしいので移植が楽ってところが良いと思っています。何か質問があれば@peterpanpppまでよろしくです。(答えられるかわかりません笑)