diff options
Diffstat (limited to 'docs/creating_a_rock.md')
-rw-r--r-- | docs/creating_a_rock.md | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/docs/creating_a_rock.md b/docs/creating_a_rock.md new file mode 100644 index 00000000..e93505ac --- /dev/null +++ b/docs/creating_a_rock.md | |||
@@ -0,0 +1,438 @@ | |||
1 | # Creating a rock | ||
2 | |||
3 | So, you wrote a Lua package (containing one or more modules) and want to make | ||
4 | it available to users through LuaRocks. The process consists essentially of | ||
5 | the following steps: | ||
6 | |||
7 | * Writing a rockspec file | ||
8 | * Publishing your code online | ||
9 | * Submitting a rockspec for inclusion in the rocks server | ||
10 | |||
11 | ## Writing a rockspec | ||
12 | |||
13 | A rockspec file is the metadata file for your package, containing all the | ||
14 | information LuaRocks needs in order to fetch, build and install your package. | ||
15 | The [Rockspec format](rockspec_format.md) supports various kinds of build | ||
16 | systems, but in this tutorial we'll use LuaRocks' own built-in build system -- | ||
17 | that's why we're listing "Writing a rockspec" as the first step. We'll use the | ||
18 | rockspec in place of a Makefile. | ||
19 | |||
20 | A rockspec is actually a Lua file, but it is loaded in an empty environment, | ||
21 | so there are no Lua functions available. A skeleton for a basic rockspec looks | ||
22 | can be written by hand or generated using [luarocks write_rockspec](luarocks_write_rockspec.md). | ||
23 | It may look like this: | ||
24 | |||
25 | ```lua | ||
26 | package = "LuaFruits" | ||
27 | version = "1.0-1" | ||
28 | source = { | ||
29 | url = "..." -- We don't have one yet | ||
30 | } | ||
31 | description = { | ||
32 | summary = "An example for the LuaRocks tutorial.", | ||
33 | detailed = [[ | ||
34 | This is an example for the LuaRocks tutorial. | ||
35 | Here we would put a detailed, typically | ||
36 | paragraph-long description. | ||
37 | ]], | ||
38 | homepage = "http://...", -- We don't have one yet | ||
39 | license = "MIT/X11" -- or whatever you like | ||
40 | } | ||
41 | dependencies = { | ||
42 | "lua >= 5.1, < 5.4" | ||
43 | -- If you depend on other rocks, add them here | ||
44 | } | ||
45 | build = { | ||
46 | -- We'll start here. | ||
47 | } | ||
48 | ``` | ||
49 | |||
50 | This should be saved in a file called luafruits-1.0-1.rockspec. The name must | ||
51 | contain lowercase versions of the "package" and "version" fields, or else | ||
52 | LuaRocks will complain. | ||
53 | |||
54 | There is some missing stuff in our rockspec which we will fill later, such as | ||
55 | the source.url and description.homepage fields. We'll add those when we upload | ||
56 | our sources whatever server you choose to. | ||
57 | |||
58 | Right now our focus will be on the "build" section. | ||
59 | |||
60 | ### Building a module | ||
61 | |||
62 | LuaRocks supports a number of "build types": "make" for using Makefiles, | ||
63 | "cmake" for using CMake, etc. In this tutorial, however, we'll use its | ||
64 | built-in build system, called the "builtin" type. | ||
65 | |||
66 | ```lua | ||
67 | build = { | ||
68 | type = "builtin" | ||
69 | -- Now we need to tell it what to build. | ||
70 | } | ||
71 | ``` | ||
72 | |||
73 | In the "builtin" type, we add a subtable called "modules", in which keys are | ||
74 | module names in Lua notation, and values indicate how to build them. This | ||
75 | example shows the various possibilities supported: | ||
76 | |||
77 | ```lua | ||
78 | build = { | ||
79 | type = "builtin", | ||
80 | modules = { | ||
81 | -- A simple module written in Lua | ||
82 | apricot = "src/apricot.lua", | ||
83 | |||
84 | -- Note the required Lua syntax when listing submodules as keys | ||
85 | ["apricot.seeds"]("apricot.seeds") = "src/apricot/seeds.lua", | ||
86 | |||
87 | -- A simple module written in C | ||
88 | banana = "src/banana.c", | ||
89 | |||
90 | -- C modules can span multiple files. | ||
91 | cherry = {"src/cherry.c", "src/cherry_pie.c"}, | ||
92 | |||
93 | -- C modules also support an extended syntax, supporting | ||
94 | -- cross-platform specifications of C defines, libraries and | ||
95 | -- paths for external dependencies. | ||
96 | date = { | ||
97 | sources = {"src/date.c", "src/cali_date.c", "src/arab_date.c"}, | ||
98 | defines = {"MAX_DATES_PER_MEAL=50"}, | ||
99 | libraries = {"date"}, | ||
100 | incdirs = {"$(LIBDATE_INCDIR)"}, | ||
101 | libdirs = {"$(LIBDATE_LIBDIR)"} | ||
102 | } | ||
103 | } | ||
104 | } | ||
105 | ``` | ||
106 | |||
107 | Since modules written in Lua do not need to be compiled, LuaRocks only needs | ||
108 | to know where they are in your source directory tree in order to copy them to | ||
109 | the proper place on installation (see the "apricot" and "apricot.seeds" in the | ||
110 | above example). | ||
111 | |||
112 | Similarly, for C code with no dependencies on external libraries, it suffices | ||
113 | to say where the sources are and LuaRocks will invoke the appropriate compiler | ||
114 | and linker for the platform. You can use a simple string value for single-file | ||
115 | modules, such as the "banana" example above or an array value for multiple | ||
116 | source files (as in the "cherry" example). | ||
117 | |||
118 | To make writing rocks for projects with a common directory layout even easier, | ||
119 | the "builtin" build type recursively copies all files and directories it finds | ||
120 | in a folder called "./lua" (if it exists) to the same place as other Lua | ||
121 | files. It's almost as if an entry had been added to `modules` for every file | ||
122 | in `lua`, except that the files will only be copied - files ending in ".c" | ||
123 | won't be compiled. | ||
124 | |||
125 | #### Depending on other rocks | ||
126 | |||
127 | You can specify that your code depends on other rocks, so you can use modules | ||
128 | from other rocks in your code and have them be automatically downloaded and | ||
129 | installed when a user installs your rock. | ||
130 | |||
131 | Suppose we need the modules from the "luaknife" rock, in order to cut our | ||
132 | fruits. But we need version later than 2.3 of luaknife, because we're using | ||
133 | functions that were introduced in that version. We'll add that to our | ||
134 | dependencies table: | ||
135 | |||
136 | ```lua | ||
137 | dependencies = { | ||
138 | "lua >= 5.1, < 5.4", | ||
139 | "luaknife >= 2.3" | ||
140 | } | ||
141 | ``` | ||
142 | |||
143 | Note that the dependency on Lua itself is also given in that table, and that | ||
144 | it uses two constraints on its version at once: `>= 5.1` and `< 5.4`. When | ||
145 | several constraints are used like this, they all have to be satisfied. | ||
146 | Therefore, `lua >= 5.1, < 5.4` means that our rock supports Lua `5.1`, `5.2`, | ||
147 | and `5.3`, but not yet-to-be-released `5.4`. There are a few other operators | ||
148 | for specifying version constraints, see | ||
149 | [Rockspec format](rockspec_format.md#dependency-information). | ||
150 | |||
151 | #### C modules linking to external libraries | ||
152 | |||
153 | *If your code does not use third-party libraries, you may skip this subsection.* | ||
154 | |||
155 | For building C code that links to C libraries, you can use the long syntax | ||
156 | given in the "date" example above, in which sources are listed in the | ||
157 | "sources" subtable. You need to specify the libraries to be linked in the | ||
158 | "libraries" subtable. The library name is specified in a platform-independent | ||
159 | way: in the above example, `libraries={"date"}` will result in `-ldate` for | ||
160 | GCC on Unix and `DATE.LIB` for MSVC on Windows. (Note that if this is not | ||
161 | appropriate, the rockspec format allows [per-platform | ||
162 | overrides](platform_overrides.md).) If you need to link code that uses | ||
163 | libraries, you need to tell LuaRocks where to find them. You do this by adding | ||
164 | a new section to the rockspec: | ||
165 | |||
166 | ```lua | ||
167 | external_dependencies = { | ||
168 | LIBDATE = { | ||
169 | header = "libdate.h" | ||
170 | } | ||
171 | } | ||
172 | ``` | ||
173 | |||
174 | Adding the "external_dependencies" table will make LuaRocks search for the | ||
175 | external dependencies in its lookup path (on Unix the defaults are | ||
176 | `/usr/local` and `/usr`; on Windows, which doesn't have a standard for | ||
177 | development trees, you'll probably have to specify it yourself through the | ||
178 | [Config file format](config_file_format.md) or the [luarocks](luarocks.md) when | ||
179 | invoking "luarocks"). We give a hint to LuaRocks, the `libdate.h` header, so | ||
180 | it can test whether the development package is really there (on many Linux | ||
181 | distros, one needs to install "-dev" packages in order to have all headers and | ||
182 | libraries needed for compilation available, so header files are a good hint). | ||
183 | In this case, for example, it would look for `/usr/local/include/libdate.h` | ||
184 | and `/usr/include/libdate.h` on Unix. If you (or your users) have LibDate | ||
185 | installed elsewhere, it's always possible to tell LuaRocks so through the | ||
186 | command-line, passing for example `LIBDATE_DIR=/opt/libdate` as an argument. | ||
187 | |||
188 | When LuaRocks succeeds finding an external dependency, it creates special | ||
189 | variables for it which can be used in incdirs and libdirs fields. The example | ||
190 | above shows two such variables, `LIBDATE_INCDIR` and `LIBDATE_LIBDIR` being | ||
191 | use. It's important to always pass those variables: if LibDate happened to be | ||
192 | in the system lookup path of your compiler, compilation would succeed without | ||
193 | those variables, but they would fail in a user's system where they are | ||
194 | somewhere else, such as in the `LIBDATE_DIR=/opt/libdate` example given | ||
195 | earlier. | ||
196 | |||
197 | ### Using LuaRocks as a build system | ||
198 | |||
199 | Now that your build section is written, you can use LuaRocks as a build system | ||
200 | and have it compile and install your code as a rock. Just type: | ||
201 | |||
202 | ``` | ||
203 | luarocks make | ||
204 | ``` | ||
205 | |||
206 | and it will do its thing. Like "make", it will look for the appropriate rules | ||
207 | file (in our case, the rockspec) in the current directory and then will | ||
208 | proceed to build and install the package in your rocks tree, assuming the | ||
209 | sources are in the current directory as well. | ||
210 | |||
211 | ### Including documentation and other files | ||
212 | |||
213 | In the build section you can include arbitrary files through the | ||
214 | "copy_directories" table. In this table you can list directories in your rock | ||
215 | that will be copied to the target rocktree during installation. | ||
216 | |||
217 | ```lua | ||
218 | copy_directories = { "doc", "test" } | ||
219 | ``` | ||
220 | |||
221 | A special case for these is the "doc" directory for locally installed | ||
222 | documentation. Documentation installed this way will be available on the | ||
223 | target system through | ||
224 | |||
225 | ``` | ||
226 | luarocks doc ROCKNAME | ||
227 | ``` | ||
228 | |||
229 | ## Publishing your code online | ||
230 | |||
231 | Now, to complete the rockspec for public consumption we need to fill the | ||
232 | sources.url field. For that, we need the code to be available online. We have | ||
233 | two approaches for that: if you have your source code in an online repository | ||
234 | such as [GitHub](GitHub)(https://github.com), you may use that directly. | ||
235 | Alternatively, you can publish a tarball with the sources on the web. | ||
236 | |||
237 | ### Method 1: using a repository such as Github | ||
238 | |||
239 | Make sure your release is tagged in your repository. Failing to use a tag will | ||
240 | make LuaRocks point at your latest development code, making it a "moving | ||
241 | target". LuaRocks users should be directed to a specific version of your code. | ||
242 | (If you want to make a rockspec pointing at your repository's HEAD, use "scm" | ||
243 | as the version number of your rockspec -- this will identify it as a rockspec | ||
244 | for the "unstable" version.) | ||
245 | |||
246 | In the `source.url` field, enter the URL for your repository using your SCM tool | ||
247 | as the protocol. For git repositories, you don't need use the .git extension. | ||
248 | Then, use the `source.tag` entry to specify your tag. For example, this is how | ||
249 | our source section would look like if we hosted LuaFruits on Github: | ||
250 | |||
251 | ```lua | ||
252 | source = { | ||
253 | url = "git://github.com/me/luafruits", | ||
254 | tag = "v1.0", | ||
255 | } | ||
256 | ``` | ||
257 | |||
258 | To tag a release in Git, use the "git tag" command, and remember to pass the | ||
259 | "--tags" flag to "git push": | ||
260 | |||
261 | ``` | ||
262 | git tag v1.0 | ||
263 | git push --tags | ||
264 | ``` | ||
265 | |||
266 | Or use GitHub's "Releases" interface. | ||
267 | |||
268 | LuaRocks also supports other source control management systems, such as CVS | ||
269 | (cvs://), Subversion (svn://) and Mercurial (hg://). | ||
270 | |||
271 | Don't worry about deployment complications when using this method. When you | ||
272 | submit a rock for inclusion in the LuaRocks repository, a .src.rock file is | ||
273 | generated which contains a copy of the source code, so LuaRocks users won't | ||
274 | need to have Git or any other such tool installed to use your rock. | ||
275 | |||
276 | ### Method 2: publishing a tarball | ||
277 | |||
278 | When using a zip or tarball, by default LuaRocks expects it to contain a | ||
279 | top-level directory with your code. This directory should be named the same as | ||
280 | the tarball itself (but without the .zip or .tar.gz extension) and its | ||
281 | recommended that this name be the lowercase name of the package with its | ||
282 | version number (but without the LuaRocks revision number). If your code is | ||
283 | located in a different directory, please see [Rockspec | ||
284 | format](rockspec_format.md) for instructions. In our example, we should make a | ||
285 | tarball with the following contents: | ||
286 | |||
287 | ``` | ||
288 | luafruits-1.0/ | ||
289 | luafruits-1.0/src/apricot.lua | ||
290 | luafruits-1.0/src/apricot/seeds.lua | ||
291 | luafruits-1.0/src/banana.c | ||
292 | luafruits-1.0/src/cherry.c | ||
293 | luafruits-1.0/src/cherry_pie.c | ||
294 | luafruits-1.0/src/date.c | ||
295 | luafruits-1.0/src/cali_date.c | ||
296 | luafruits-1.0/src/arab_date.c | ||
297 | ``` | ||
298 | |||
299 | Note that the rockspec itself doesn't need to be stored in the tarball | ||
300 | (actually, storing the final rockspec inside the package is a chicken-egg | ||
301 | problem because rockspecs can contain the source.md5 field with a checksum of | ||
302 | the tarball). | ||
303 | |||
304 | It's important to note that LuaRocks does not enforce the internal structure. | ||
305 | Our example only has a src/ subdirectory because the build rules listed above | ||
306 | used it (we could have done without it if we wanted to). The tarball could | ||
307 | contain other files as well, such as licenses and documentation. The only | ||
308 | convention used here is the top level directory name, and if desired this can | ||
309 | be overridden in the rockspec using the sources.dir field. So, now we pack our | ||
310 | code. On Unix, for example, that would be: | ||
311 | |||
312 | ``` | ||
313 | tar czvpf luafruits-1.0.tar.gz luafruits-1.0/ | ||
314 | ``` | ||
315 | |||
316 | And now we're ready to publish the tarball online. You can upload it to any | ||
317 | public web server; if you need hosting space, you can use the Pages feature | ||
318 | from [GitHub](GitHub)(https://github.com). Your source section would then look | ||
319 | something like this: | ||
320 | |||
321 | ```lua | ||
322 | source = { | ||
323 | url = "http://me.github.com/luafruits/luafruits-1.0.tar.gz" | ||
324 | } | ||
325 | ``` | ||
326 | |||
327 | ## The completed rockspec | ||
328 | |||
329 | We're ready to complete our rockspec. By now it will look like this: | ||
330 | |||
331 | ```lua | ||
332 | package = "LuaFruits" | ||
333 | version = "1.0-1" | ||
334 | source = { | ||
335 | url = "git://github.com/me/luafruits", | ||
336 | tag = "v1.0", | ||
337 | } | ||
338 | description = { | ||
339 | summary = "An example for the LuaRocks tutorial.", | ||
340 | detailed = [[ | ||
341 | This is an example for the LuaRocks tutorial. | ||
342 | Here we would put a detailed, typically | ||
343 | paragraph-long description. | ||
344 | ]], | ||
345 | homepage = "http://me.github.com/luafruits", | ||
346 | license = "MIT/X11" | ||
347 | } | ||
348 | dependencies = { | ||
349 | "lua >= 5.1, < 5.4", | ||
350 | "luaknife >= 2.3" | ||
351 | } | ||
352 | external_dependencies = { | ||
353 | LIBDATE = { | ||
354 | header = "libdate.h" | ||
355 | } | ||
356 | } | ||
357 | build = { | ||
358 | type = "builtin", | ||
359 | modules = { | ||
360 | apricot = "src/apricot.lua", | ||
361 | ["apricot.seeds"]("apricot.seeds") = "src/apricot/seeds.lua", | ||
362 | banana = "src/banana.c", | ||
363 | cherry = {"src/cherry.c", "src/cherry_pie.c"}, | ||
364 | date = { | ||
365 | sources = {"src/date.c", "src/cali_date.c", "src/arab_date.c"}, | ||
366 | defines = {"MAX_DATES_PER_MEAL=50"} | ||
367 | libraries = {"date"}, | ||
368 | incdirs = {"$(LIBDATE_INCDIR)"}, | ||
369 | libdirs = {"$(LIBDATE_LIBDIR)"} | ||
370 | } | ||
371 | }, | ||
372 | copy_directories = { "doc", "test" } | ||
373 | } | ||
374 | ``` | ||
375 | |||
376 | ## Submitting a rockspec for inclusion in the rocks server | ||
377 | |||
378 | ### Web upload | ||
379 | |||
380 | This is the simplest step: just create an account at | ||
381 | https://luarocks.org/register and upload your rockspec. It will automatically | ||
382 | be included in the public LuaRocks repository once the mirror propagates the | ||
383 | change. Users of LuaRocks >= 2.2 will be able to download your package | ||
384 | immediately. We will usually publish both the .rockspec file and the | ||
385 | appropriate .rock file in the server. | ||
386 | |||
387 | ### Pack command | ||
388 | |||
389 | You can also create .rock files yourself. If you run the [luarocks | ||
390 | pack](luarocks_pack.md) command on your rockspec, like this: | ||
391 | |||
392 | ``` | ||
393 | luarocks pack luafruits-1.0-1.rockspec | ||
394 | ``` | ||
395 | |||
396 | you will get a file called luafruits-1.0-1.src.rock, which contains the | ||
397 | rockspec itself and your sources. Since it contains the source code, users | ||
398 | won't need to use Git or whatever tool specified in source.url to fetch the | ||
399 | code; it's all in the rock. | ||
400 | |||
401 | If you have the rock installed in your local tree, you can also pack the | ||
402 | binaries you just built: | ||
403 | |||
404 | ``` | ||
405 | luarocks pack luafruits | ||
406 | ``` | ||
407 | |||
408 | (The version is optional, latest is assumed.) This will create a file with a | ||
409 | name such as luafruits-1.0-1.linux-x86.rock. | ||
410 | |||
411 | ### Upload command | ||
412 | |||
413 | When you've verified that creating the rock works, you can upload it to the | ||
414 | LuaRocks server with the [luarocks upload](luarocks_upload.md) command: | ||
415 | |||
416 | ``` | ||
417 | luarocks upload luafruits-1.0-1.rockspec --api-key=<your API key> | ||
418 | ``` | ||
419 | |||
420 | You can get an API from the [settings page of your account on the LuaRocks web | ||
421 | site](https://luarocks.org/settings/api-keys). | ||
422 | |||
423 | ## Conclusion | ||
424 | |||
425 | And we're done -- by writing a simple rules file which simply describes which | ||
426 | sources compose the project and which libraries they use, we actually achieved | ||
427 | a lot behind the scenes: LuaRocks takes care of using the right compiler for | ||
428 | your platform (GCC? MSVC?), passing the right flags (-fpic? -shared? -bundle | ||
429 | -undefined dynamic_lookup?) and checking external dependencies (/usr/lib? | ||
430 | /usr/local/lib? Is it really there?). Getting all these little portability | ||
431 | details right is not always easy to do on hand-written Makefiles, so that's | ||
432 | why we recommend using LuaRocks's own build system whenever possible. There | ||
433 | are many other features of LuaRocks we haven't covered in this tutorial | ||
434 | (per-platform overrides, support for command-line scripts, etc.), but this | ||
435 | should get you started. | ||
436 | |||
437 | |||
438 | |||