Use luabind to embed Lua into a C ++ Project

Source: Internet
Author: User

Opening part-Environment hypothesis

By: HengStar (Xin Heng)

Address: http://blog.csdn.net/gongxinheng/archive/2009/07/25/4380526.aspx

(Although I am not good at writing or having a high level, it is not easy to write an article and share some small achievements with you ~ For this reason, please indicate the source of the reprinted content: Thank you for your cooperation. ^_^ by the way, you can make a small advertisement. Hey hey, if you are interested in communication, you can add the QQ group: 31249966, if you think there is something wrong with my article, please point it out .. QQ chat -. -QQ: 9292492 at the same time also thanks to the translation of prawns linkerlin luabind document to the English level is not high I a lot of help ^ document here: http://blog.csdn.net/linkerlin/archive/2008/04/06/2254725.aspx)
Opening remarks (PS: Skip this example if you think it's okay -. -#): I am an online game developer. I first came into contact with Lua scripts. As the script technology in the original project is lagging behind, it is inconvenient for developers to use, so I want to introduce a good script mechanism, after learning about the power of Lua and its wide application in the gaming industry, I did not hesitate to choose it. After studying Lua for a period of time, I found that it is not easy to add this item to a large project that is already on the market. There are too many things to consider, after all, the differences in the C ++ and Lua languages are quite large. It takes a lot of effort to fully implement the convenient interaction between C ++ and Lua, especially when some object-oriented features such as polymorphism and inheritance are used in a wide range of projects, and there is not much time for yourself, fortunately, I learned from my colleagues that there is a luabind role and it is also open-source. I am now preparing to study it together, because most of the old Code cannot be transplanted, we encountered a series of troubles in the embedded work -. -The next step is coming, but after several days of hard work, it has been successfully put into use in the project, but the new version has not yet been released... If you don't talk nonsense, start with the question)

1. Add Luabind to the Project
Required: Luabind source code, Lua SDK and source code, Boost source code
Create a static Link Library Project in VS and add all the files in the src directory under the Luabind source code path to the project, compile it as a Luabind static link library (you need to Include the root directory after the Luabind source code is decompressed, The Include file directory of Lua, And the Boost source code root directory. Pay attention to the engineering options, at that time, the structure alignment mode of our project options was "one byte alignment", while the default byte alignment mode was used for compiling the Luabind static Link Library,) load the compiled static Link Library to the C ++ project;

2. Add Lua to the Project
Same as above

3. Create a LuaManager class
Header files to be included:
Create a manager class dedicated for managing Lua script engine. You can use Singleton (single-piece) technology (see design mode for details).
Class luamanager
{
Lua_state * m_pl; // Lua state, initially null
... For member methods, see
};
Generally, you need to implement the following methods (for reference only. You can use a method that is more suitable for your project based on different engineering needs ):
1. INIT (initialization): used to initialize LUA-related content. Sample Code:
Bool luamanager: Init ()
{
If (! M_pL) // ensure that only one Initialization is performed.
{
M_pL = luaL_newstate (); // create a Lua status
If (! M_pL) return false;
LuaL_openlibs (L); // open all the Lua libraries for this Lua status
Luabind: open (L); // open the luabind library for this Lua status
}
Return registerAll (); // see the following
}
2. registerAll (register all required content ):
Friends who have learned Lua must know that functions in C/C ++ need to be registered for calls in Lua. If you use the method provided by Lua, it will be very troublesome, as the scale of the project expands, it will increase the management difficulty. This is why I chose luabind. It provides a very convenient mechanism to encapsulate the binding of C/C ++ classes, functions have been registered, and even the global variables declared in C/C ++ can be directly registered to Lua for use. (because our project code volume is large, to facilitate maintenance, I divide this method into two parts. One is specifically used to register registerClasses OF THE C ++ class and registerFunctions used to register the global function. Also, we will consider adding registerVars to register the global variable ), sample Code:
Bool LuaManager: registerAll ()
{
// The following is the registration of global functions
Module (L)
[
Def ("myfunc", & myfunc ),
Def ("specialfunc", & Specialfunc)
]
// The following is the registration of Classes
Module (L)
[
Class _ ("Testclass") // base class
. Def (constructor () // Constructor
. Def ("print_string", & testclass: print_string) // virtual member function
,
// Subclass. Note that the base class must also be specified in the template parameters.
Class _ ("Myclass ")
. Def (constructor () // Constructor
. Def ("print_string", & myclass: print_string) // member function
]
Return true; // The registration failure has not been studied yet. For now, let's assume that the registration will always succeed.
}
For more details, see the luabind documentation.
Http://blog.csdn.net/linkerlin/archive/2008/04/06/2254725.aspx
3. loadScript: used to load the compiled Lua script file (the compiled binary Luac script file is recommended for high efficiency). Sample Code:
Bool LuaManager: loadScript (const string & fname)
{
If (luaL_loadfile (L, fname. c_str () // you can use the luaL_dofile macro to execute the Lua script immediately.
{
Cerr return false;
}
Return true;
}

Iv. initialize LuaManager
It's not much to say about such a simple job... Call init directly and use loadScript to load the corresponding script file.

Summary:
The content in this article is relatively simple. It quickly summarizes the environment hypothesis of luabind embedded in the C ++ project. A lot of information can be found in this document, so I will not want to talk about it more here, if you have any questions, please contact me and try your best to answer them ^

Here we can show that Lua is powerful in that it supports the function of dynamically loading scripts. My current idea is to provide the interface for loading Lua scripts to a GM command in the game, in the future, scripts will be updated and released. simply re-load these scripts with the GM command to complete the server script update, you don't need to restart the server or even compile the server again (the old script logic in the current project has always been associated with the server code, so every time you change the script, you need to compile the server, which is very annoying ...)

Next article, I will mention some of the C ++ language features I have encountered in my project that cause some interaction difficulties with Lua, as well as my solutions and some simple interaction mechanisms I have learned based on luabind source code, coming soon ^

This article from the CSDN blog, reproduced please indicate the source: http://blog.csdn.net/gongxinheng/archive/2009/07/25/4380526.aspx

 

Article 2-language differences and solutions (preliminary)

By: HengStar (Xin Heng)

Link: http://blog.csdn.net/gongxinheng/archive/2009/07/26/4381217.aspx

Through the introduction in the previous article, we have learned the basic setup method of luabind. This article will use my own experience in practice, examples are provided to illustrate some problems caused by language differences that may be encountered during actual development and solutions that I have tried.

I. Strict matching of the default VS parameter count
As we all know, the default parameters in C ++ can bring us great convenience. Observe the following code:
View plaincopy to clipboardprint?
# Define FOOD_DOGFOOD 0
# Define FOOD_RICE 1
Bool feedDog (const char * dogName, int foodType = FOOD_DOGFOOD );
# Define FOOD_DOGFOOD 0
# Define FOOD_RICE 1
Bool feedDog (const char * dogName, int foodType = FOOD_DOGFOOD );
PS: This function declaration is just unexpected and has no special meaning (because I also have a cute puppy ^). Suppose we have many dogs, or a Pet Training Base. ^ when we feed a dog, we use dogname to determine which dog to feed, the default foodtype parameter food_dogfood is provided for the type of food to be fed (because I usually only give it dog food). Then, when I call this function, I often write feeddog ("Bean") like this "); use the default food type parameter. Due to habits, I use the def ("feeddog", & feeddog) of luabind to register this function to Lua and use feeddog ("Bean ") when executing the Lua script, the following error occurs: "No matching overload found, candidates: bool feeddog (char const *, INT)", that is, no matching overload function is found in the call, but there are two candidate feeddog functions. Okay, it's big here. Let's see what's going on. For the moment, the macro food_dogfood defined in C ++ cannot be used in Lua, even if you use a number 0, because luabind strictly matches the number of parameters, the registered function has several parameters (including the default parameters), which must be set in the Lua script.
Solution: All parameters (including default parameters) must be written when called in Lua)
View plaincopy to clipboardprint?
Feeddog ("Bean", 0)
Feeddog ("Bean", 0)
Of course, you can also define pseudo enumeration in Lua (I name it myself ^)
View plaincopy to clipboardprint?
Food_dogfood = 0
Feeddog ("Bean", food_dogfood)
Food_dogfood = 0
Feeddog ("Bean", food_dogfood)

Remember: Do not expect all the conveniences brought about by C ++ to be used in Lua.

2. String pointer vs nil type
Now, let's start training the dogs. First, I need to call the dogs I want to train. We have the following functions to call the dogs by name.
View plaincopy to clipboardprint?
Bool calldog (const char * dogname)
{
If (dogname = NULL) return callall ();
Else return call (dogname );
}
Bool calldog (const char * dogname)
{
If (dogname = NULL) return callall ();
Else return call (dogname );
}
Maybe I want to call all the dogs at one time, so when I implement this function to pass null as a parameter, it means to call all the dogs. You know, in Lua, Nil is used to indicate null values. However, there are some differences between nil and null in C ++ in Lua. null in C ++ is usually defined as a number 0, in Lua, Nil is an independent type, nil ~ = 0, but we still hope that it can be converted to null value in C ++, so we try to call in Lua as follows:
View plaincopy to clipboardprint?
CallDog (nil)
CallDog (nil)
We were disappointed to see from the output results that "No matching overload found, candidates: bool callDog (char const *)"
Oh! Shit! (This is the first response I saw at the time -. -#), it seems that the result is not as perfect as we expected. In Lua, we will try nil as a type. In luabind, we will make a strict parameter type determination. nil is not a string, in addition, there is no pointer type in Lua, so the operation of variables in the pointer method will inevitably lead to the failure result (but not all cases are like this, character pointers are a special type, some allowed conversions will be mentioned later ). Someone may think like this: "Well, since you say that NULL in C ++ is usually defined as 0, I can call it like this ".
View plaincopy to clipboardprint?
CallDog (0)
CallDog (0)
Well... It seems that we thought of it together, but after the execution, we still saw the same text from the error output... It is emphasized that luabind treats strings more with string features (such as std: string ).
Solution: when you use a registration function with the const char * parameter to determine whether the parameter is NULL, you also need to determine whether it is a NULL String, that is, "", and when you call this function in Lua, the converted C ++ code is as follows:
View plaincopy to clipboardprint?
Bool callDog (const char * dogName)
{
// DogName [0] = '/0' can be replaced by strcmp (dogName, "") = 0
If (dogName = NULL | dogName [0] = '/0') return callAll ();
Else return call (dogName );
}
Bool callDog (const char * dogName)
{
// DogName [0] = '/0' can be replaced by strcmp (dogName, "") = 0
If (dogName = NULL | dogName [0] = '/0') return callAll ();
Else return call (dogName );
}
Call in LUA:
View plaincopy to clipboardprint?
CallDog ("")
CallDog ("")

Remember: Do not pass nil or 0 to the string parameter in Lua. Use std: string instead of the string parameter in the function interface used for Lua registration, if you have to use const char *, remember to judge the level of NULL and NULL.

III. C ++ Object Pointer VS nil type
As mentioned above, character pointers are of a special type, which can be proved by differences with C ++ object pointers.
The dog's owner wants to pick up the trained dog and go home ~ Every dog has a host sign around his neck. Let's regard it as a pointer of his/her master. We have the following types that represent his/her master and have been registered in Lua.
View plaincopy to clipboardprint?
Class Person
{
Public:
Person (const string & n): name (n ){}
String name;
};
Class Person
{
Public:
Person (const string & n): name (n ){}
String name;
};
The Lua script contains the following table indicating the relationship between the dog and the master.
View plaincopy to clipboardprint?
HengStar = Person ("HengStar") -- a master
DaQiang = Person ("DaQiang") -- a master
Dogs = {"Beibei", "Doudou", "qiangqiang"} -- dog serial number table
Dog_Master = {nil, HengStar, DaQiang} -- owner of the dog serial number
HengStar = Person ("HengStar") -- a master
DaQiang = Person ("DaQiang") -- a master
Dogs = {"Beibei", "Doudou", "qiangqiang"} -- dog serial number table
Dog_Master = {nil, HengStar, DaQiang} -- owner of the dog serial number
The administrator wants to help the dog master find his dog, so we have registered a function to determine the dog-master match.
View plaincopy to clipboardprint?
Bool checkMaster (Person * realMaster, Person * dogMaster)
{
Assert (realMaster! = NULL); // This is not allowed
If (dogMaster = NULL) // note the following:
{
Cout <"A dog has no master !" <Endl;
Return false;
}
Return realMaster-> name = dogMaster-> name; // assume that the name is not repeated.
}
Bool checkMaster (Person * realMaster, Person * dogMaster)
{
Assert (realMaster! = NULL); // This is not allowed
If (dogMaster = NULL) // note the following:
{
Cout return false;
}
Return realMaster-> name = dogMaster-> name; // assume that the name is not repeated.
}
Now, the preparation is complete. Let's start a dog search and execute the following code in the Lua script.
View plaincopy to clipboardprint?
For I = 1, # dog_Master do
If (checkMaster (HengStar, dog_Master [I]) then
Print (dogs [I] .. "found the master! ")
Break
End
End
For I = 1, # dog_Master do
If (checkMaster (HengStar, dog_Master [I]) then
Print (dogs [I] .. "found the master! ")
Break
End
End
Output result:
A dog has no master
Doudou found the master.

At this point, the example is complete, and the readers have observed the conclusions I want to explain ~ That's right, it's a registration function with a pointer to a C ++ registration class object as a parameter. When called in Lua, it allows the conversion from nil to NULL in C ++, this is exactly what is different from character pointers. It is also the power of luabind.
In the above sample code, for I = 1, # dog_Master will traverse all elements in dog_Master and pass the corresponding value to the second parameter of the checkManager function, the value of the first element of dog_Master is nil, which is converted to NULL in luabind and passed to checkMaster. Therefore, a dog has no master.

PS: The display method of this sample code may be a little too far-fetched, but it can indicate that the problem I want to talk about is achieved.

Remember: In luabind, the parameter type passed in by Lua matches the parameter type of the C ++ registration function. If the parameter is a C ++ registration Class Object Pointer, nil is converted to NULL.

This article from the CSDN blog, reproduced please indicate the source: http://blog.csdn.net/gongxinheng/archive/2009/07/26/4381217.aspx

 

Article 3-language differences and solutions (advanced)

By: HengStar (Xin Heng)

Through the previous two articles, we have gained a better understanding of luabind. Next, let's make it easier. The example below may be a bit against common sense, but I did encounter it in the project, so here we will give you a better understanding of the luabind mechanism.

1. Cheat compiler? -- Dog stunt
Well, ladies and gentlemen, the exciting time is coming. Now is the dog's happy time. The cute dogs are about to perform their own performances ~ Let's wait and see...
Let's take a look at the following code:
# Include

Using namespace std;

Class Dog // Dog Base class

{};

Class Chihuahua: public Dog // doll

{

Public:

Bool wallow () // rollback

{

Cout

Return true;

}

};

Class Gundogs: public Dog // hound

{

Public:

Bool hunt () // hunting

{

Cout <"I'm hunting! "<Endl;

Return true;

}

};

Class podog: public Dog // lady

{

Public:

Bool highjump () // High Jump

{

Cout <"I'm jumping! "<Endl;

Return true;

}

};

Typedef bool (Dog: * dogact) (); // member function pointer for Dog stunt

Bool Dogshow_impl (Dog * dog, dogact act)

{

Return (dog-> * act )();

}

Int main ()

{

Dog * myDog = new Poodle;

Dogshow_impl (myDog, & Poodle: highjump); // Let's get started.

Return 0;

}

All right, all the code above. Let's guess the output...
Unfortunately, the trainer (compiler) began to complain, "I want to see a Dog, not a Poodle ", maybe this trainer is a fool, but it is designed like this. He is only responsible for executing the program. The second parameter required by the Dogshow_impl function is a member function pointer of the Dog Base class, however, it is illegal to pass the member function pointer of a subclass Poodle (if you cannot understand it, refer to related C ++ books, such as C ++ Primer). because the base class cannot understand which similar member functions (with the same function prototype) will appear in the subclass at all, well, in this case, I 'd like to figure out a way to get through it ~ Let's put a veil on the performer to make it disguise (forced conversion) into a so-called dog (base class)

# Define dogshow (dogpt, act) Dogshow_impl (dogpt, (dogact) act)

Then I
Dogshow_impl (myDog, & Poodle: highjump); // Let's get started.

Change
Dogshow (myDog, & Poodle: highjump); // Let's get started.

"Good", the animal trainer praised and asked myDog to execute its highjump method, so the output was:

I'm jumping!
OK, our goal has been achieved (but I have to admit that this design pattern is very failed ...), I can now pass any pointer of a dog and the member function corresponding to any signature as a parameter, but this is always a spoofing behavior, and the eyes of the animal trainer have escaped, however, it does not necessarily escape the review of the judges (luabind.

First, the macro definition is not supported by lua, so we cannot use dogshow to register it. Currently, we can only use the Dogshow_impl function by directly registering it in lua, let's register all classes and methods.

We call this in lua with luck

MyDog = Poodle ()

Dogshow_impl (myDog, myDog. highjump)

Unfortunately, the Code fails to be executed for the following reasons:
First of all, luabind has a strict type judgment. This is the same as the principle of generating compilation errors in the initial C ++ code, so it will not be repeated, but the essence is not this, myDog. highjump is a function type in lua and is not a member function pointer type. Therefore, the parameter type judgment fails. What should I do? You can't just use it for this reason. Use your brains to find a solution...

Solution:

Provides my own solution:

First of all, if you have to design in this mode, I can declare all the sub-classes in the base class to use the member functions in lua as virtual functions. In this way, the following method is added to the Dog class:

Class Dog // Dog Base class

{

Public:

Virtual bool hunt ();

Virtual bool highjump ();

.......

};

Obviously this is not a good method. We recommend that you abstract these methods in the base class, for example, rename them perform, so that the base class only needs a virtual bool perform () (Of course, the virtual function of this base class must also be registered). The subclass can implement it by itself. The most important thing is that it can be correctly called in Lua, then we need to encapsulate the dogshow_impl function in one layer. The parameters of the second member function pointer can be replaced by const luabind: object. luabind: object can receive the function type in Lua, you can also use call_function to directly call it and use parameter 1 (basic dog pointer) as the call_function parameter (For details, refer to the luabind document ), next, we need to declare a global base class object in Lua, which is used to select the virtual function called. Let's look at the transformed code ~

First, encapsulate a layer in C ++

Bool lua_dogshow (dog * dog, const luabind: Object & func)

{

Using namespace luabind;

Call_function (Func, dog); // This func is a Lua function, and dog is the caller.

Return true;

}

Register this function to Lua

Then write the following code in Lua:

Dog = dog () // global, used to "select" the virtual function used to call

Function myfunc ()

Local mydog = poodle ()

-- Note that the dog. highjump here is equivalent to the member function pointer. The highjump is registered through the base class.

Lua_dogshow (mydog, dog. highjump)

End

When the myfunc function in Lua is called in C ++, the following output is displayed:
I'm jumping!

This article from the csdn blog, reproduced please indicate the source: http://blog.csdn.net/gongxinheng/archive/2009/08/04/4409530.aspx

 

-----------------------------------------

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.