WoWInterface (
-   Lua/XML Help (
-   -   Include files (

doofus 09-12-18 01:44 AM

Include files
Hello guys

I have a rather large addon which is in a single .lua file, and it has about 15,000 lines and it is hard to navigate. Because lua variables are global I precede them with "local" so they can only be seen in my own file and avoid namespace issues with other addons. Because everyting is in one .lua file I do not have to worry about declarations of functions and variables and only make sure I declare them in the right order.

I want to split this large .lua file into smaller files just for ease of editing purposes.

In C/C++ I would simply do, #include "file1.c". With the "#include" the C compiler simply merges source files together as one might do by hand. file1.c would not compile on its own of course, it is just a convenient way to split a large source code file into chunks without worrying too much about externs and linkage.

That is in the C world. Is there a way to do the same in wow's lua?


VincentSDSH 09-12-18 03:51 AM

In short: No, you can't create a merge in that way.

If you break things out into individual files they have their own context (e.g, locals are local to that space, etc) which is a good thing for managing large amounts of code and simplifies design and debugging.

Those file segments have access to as shared namespace that is passed to each segment -- to capture it, place " local addonName, nameSpace = ... " (the first var is the string-name of the addon, the second is the namespace table) at the top of each file.

If you just want to break things apart, store your addon-global vars in the namespace table, then you can declare the file-order in the .toc file, which loads and executes in order, iirc.

Not sure why you'd want to go through that rather than use they hyper-friendly lua function but it might get you past one-massive-why-would-you-do-that-to-yourself-file problem.

Xrystal 09-12-18 05:51 AM

You can easily split them into several files.

As Vincent said, at the top of each file put

local addonName, addonData = ...

This allows each access to the addon wide data table

Function declarations will need to be defined before they are used but I think you can forward declare them where necessary.

You then specify the files in the order they need to be.

For example:
A toc file could contain something as follows:



file3.xml could then contain this


<UI xmlns=""  xmlns:xsi=""  xsi:schemaLocation="">
    <Include file = "Core.xml" />
    <Include file = "Features.xml" />   

Core.xml could then contain this

<UI xmlns=""  xmlns:xsi=""  xsi:schemaLocation="">
    <!-- Items everything else requires access to -->
    <Include file = "Utils/Utils.xml" />
    <Include file = "Localization/Localization.xml"/>
    <Include file = "Options/Options.xml" />

As you can see each file is included in the order it needs to be processed. Later files will call functions contained in earlier specified files etc.

The Utils.xml will hold a list of files that have individual unique but addon accessible functions
The Localization.xml will hold a list of localization related files which will include one that has an addon wide table to hold the active translation values used by other files
The Options.xml will hold a list of options related files which may need access to the localization files

Further core files can be added in the Core.xml file and the files listed in Features.xml will have access to everything that was included before it.

If the file you need is a code file you can use
<script file = "file1.lua" />

to add it to the list of files to load inside an xml file.

This is the only way I know of to 'include' files in a specified order

Here is an example of a frame that requires access to functions in a source file but is also used in another source file. For example if the frame display is controlled. Most of the time though only first first file is needed and the frame just passes itself to the functions it wants to work.


<UI xmlns=""  xmlns:xsi=""  xsi:schemaLocation="">

    <!-- Include script file that will hold the functions called by the FrameToDisplay frame and functions within sourceFile2.lua -->
    <Script file = "sourceFile1.lua" />
    <!-- Layout of the FrameToDisplay Frame -->
    <Frame name="FrameToDisplay">
    <!-- Include script file that acts on FrameToDisplayFrame -->
    <Script file = "sourceFile2.lua" />


So to recap ..

TOC file can be used to list key xml/lua files in order of process
XML files can be used to include xml/lua files in order of process
Lua files are used to connect the individual code files by sharing a table amongst all the files

1. Define which parts are needed by everything ... they go in the earliest files
2. Define which parts are needed by most .. they go next
3. Define which parts are needed by some .. they go next
4. Define which parts are not needed by any .. they can go anywhere but best last
5. Define which parts are needed by some but needs others .. they go in between the related files .. after the ones they need and before the ones that needs them

I hope that helps you see how you can segregate your file into smaller files

zork 09-19-18 08:55 AM

Splitting is easy.

Just add all your files to the TOC. (This requires a restart of the WoW client if changed!)


In every addon file you have access to globals, locals and your addon namespace.

Lua Code:
  1. --addon name, addon namespace
  2. local an, ans = ...

You can add functions and objects to your addon namespace without poluting the global namespace.
Making an object global, keeping it local or adding it to the addon namespace is up to you.


doofus 09-21-18 10:15 AM

Thanks for the suggestions.

Today I have tried a major restructure, trying to split the one large .lua file into multiple smaller ones, making use of the nameSpace table.

However I am unclear about the order of loading of the .lua files (is it the order in the .toc file?) and the order of initialising static variables.

in file3 I do:


in file2 I do:

nameSpace["a"]["b"] = some_local_function();

and in file1 I do:

nameSpace["a"] = {};

The way I see it, if file1 loads first then nameSpace["a"] becomes a table. If file2 follows, it will have no problem setting nameSpace["a"]["b"] = some function. And finally, file3 can now invoke nameSpace["a"]["b"]();

But it fails in file3 saying that nameSpace["a"]["b"] is nil.

The way around it is to say in file2:

nameSpace["a"] = {};
nameSpace["a"]["b"] = some_local_function();

Then, file3 works as expected.

This begs the question, why was file1's definition not taken into account?

Fizzlemizz 09-21-18 11:05 AM

The files load in the order in the .toc.

The "NameSpace" is already a table passed in by Blizzard so you don't need to create a second one.

File 1
Lua Code:
  1. local addonName, NS = ...
  3. NS.a = {}

File 2
Lua Code:
  1. local addonName, NS = ...
  3. local function LocalTest(val)
  4.      print(val)
  5. end
  7. NS.a.Test =  LocalTest
File 3
Lua Code:
  1. local addonName, NS = ...
  2. NS.a.Test("Hi there.")

you don't add the () when assigning the function unless you want to assign the result of calling the function.

doofus 09-21-18 11:50 AM

The () after the function name was a typo here, not in the code.

I do not re-initialise the namespace, only the namespace["something"].

There is an issue with

local n, ns = ...
ns["a"] = { };

local n, ns = ...
ns["a"]["b"] = some_local_function;

local n, ns = ...
ns["a"]["b"](params); -- error, it is nil

Fizzlemizz 09-21-18 12:16 PM

If you could supply the actual code please. What you put there "seems" ok so the problem may be eslewhere.

All the [""] is unnecessary if you know the key names you can just use dots.

doofus 09-21-18 01:08 PM

I think I have found the issue, when I move variable initialisation from inside a function to the outside (static init), I forgot in some cases to delete the function initialisation resulting in the static one to be overwritten.

All times are GMT -6. The time now is 06:00 PM.

vBulletin © 2020, Jelsoft Enterprises Ltd
© 2004 - 2019 MMOUI