title | tagline |
---|---|
get involved |
creating luapower packages |
NOTE: This page is all about rules, so necessarily you will have issues with it.
There are 5 types of luapower packages:
- Lua module: written in Lua, compatible with LuaJIT2, Lua 5.1 and optionally Lua 5.2
- Lua/C module: written in C using the Lua C API, compatible with LuaJIT2, Lua 5.1 and optionally Lua 5.2
- Lua+ffi module: written in Lua using the LuaJIT ffi extension, compatible with LuaJIT2 and optionally with Lua ffi; the C library it binds to is included in the package in source and binary form
- C module: binary dependency or support library for other module; source and binary included
- other: none of the above: media/support files, etc.
- main module:
foo.lua
- submodule:
foo_bar.lua
butfoo/bar.lua
is fine too - ffi cdef module:
foo_h.lua
- test program:
foo_test.lua
- demo:
foo_demo.lua
- documentation:
foo.md
,foo_bar.md
(pandoc markdown) - C libs & Lua/C libs:
- sources:
csrc/foo/*
- build scripts:
csrc/foo/build-<platform>.sh
- platforms are named mingw32, mingw64, linux32, linux64, osx32, osx64.
- binaries (resulted from building):
- C libraries:
bin/mingw32/foo.dll
,bin/linux32/libfoo.so
- Lua/C libraries:
bin/<platform>/clib/foo[.dll|.so]
- C libraries:
- description:
csrc/foo/WHAT
(see below)
- sources:
- exclude file:
foo.exclude
(see below) - LuaJIT executable:
bin/<platform>/luajit[.exe]
These conventions allow packages to be safely unzipped over a common directory and the result look sane, and it makes it possible to extract package information and build the package database.
In order to appear on the website, docs should start with a yaml header:
---
project: cairo
tagline: cairo graphics engine
---
- the
project
field should match the git project's name - this makes the "view on github" and download buttons appear. platforms: platform1, ...
should be added for Lua packages that are platform-specific but don't have a C component (eg. [winapi]; for packages with a C component, adding the build scripts is enough to figure out the supported platforms).- a good, short tagline is important for figuring out what the module does when browsing the module list
You don't have to make a doc for each submodule if you don't have much to document for it, a single doc matching the package name would suffice.
The WHAT file is used for packages that have a C component (Lua+ffi, Lua/C or C packages), and it's used to describe that C component. Pure Lua packages don't need a WHAT file.
cairo 1.12.16 from http://cairographics.org/releases/ (LGPL license)
requires: pixman, freetype, zlib, libpng
- the first line should read
<name> <version> from <browse-url> (<license>)
- the second line should read
requires: package1, package2, ...
and it is only needed if the package has any binary dependencies. - after the first two lines and an empty line, you can type in additional notes, whatever, they aren't parsed.
The WHAT file can also be used to describe Lua modules that are developed outside of luapower (eg. [lexer]).
Extracting dependencies from the dll itself and figuring it out from there is a project for another day.
This is the .gitignore file used for excluding files between packages so that files in one packages don't show as untracked files in other package. Another way to think of it is the file used for reserving name-space in the luapower directory layout.
Example:
* ; exclude all files
!/foo* ; include files in root that start with `foo`
!/foo/ ; include the directory in root named `foo`
!/foo/** ; include the contents of the directory named `foo`, recursively
NOTE: Double-asterisk patterns are Git 1.8.2+.
- adding at least a small comment on the first line of every Lua file with a short tagline (what the module does), author and license can be a huge barrier-remover towards approaching your code (adding a full screen of legal crap on the other hand is just bad taste - IMHO).
- adding a comment on top of the
foo_h.lua
file describing the origin (which files? which version?) and process (cpp? by hand?) used for generating the file adds confidence that the C API is complete and updated. - calling
ffi.load()
without paths, custom names or version numbers keeps the module away from any decision regarding how and where the library is to be found, which in turn this allows for more freedom on how to deploy libraries. - the reason for putting cdefs in a separate file is because they may contain types that other packages might need. If this is an unlikely scenario and the API is small, you can embed the cdefs in the main module file directly.
- (subjective) I don't use
module()
to keep _G clean. For big modules with a shared namespace I make a "namespace" module and usesetfenv(1, require'foo.ns')
as the first line of every submodule (see [winapi]). - (subjective) my code is indented with tabs, and alignment inside the line is done with spaces, because I think that a fixed tabsize should not be enforced on people (plus very few editors can jump through space indentation).
- (subjective) I use Lua's naming conventions
foo_bar
andfoobar
instead of FooBar or fooBar.
Write a build script for each supported platform, based on the luapower toolchain (do not introduce additional tool requirements if you can avoid it). Building with gcc is a 2-step process, compilation and linking, becuase we want to build both static and dynamic versions the libraries.
Here's a quick gcc cheat list:
gcc -c options... files...
g++ -c options... files...
-c
: compile only (don't link; produce .o files)-O2
: enable code optimizations-I<dir>
: search path for headers (eg.-I../lua
)-D<name>
: set a#define
-D<name>=<value>
: set a#define
-U<name>
: unset#define
-fpic
or-fPIC
: generate position-independent code (required for linux64)-DWINVER=0x501
: set Windows API level to Windows XP-DWINVER=0x502
: set Windows API level to Windows XP SP2-arch i386
: OSX: create 32bit x86 binaries-arch x86_64
: OSX: create 64bit x86 binaries
gcc -shared options... files...
-shared
: create a shared library-s
: strip debug symbols (not for OSX)-o <output-file>
: output file path (eg.-o ../../bin/mingw32/z.dll
)-L<dir>
: search path for library dependencies (eg.-L../../bin/mingw32
)-l<libname>
: library dependency (eg.-lz
looks forz.dll
,libz.so
orlibz.dylib
depending on platform)-static-libstdc++
: static linking of the C++ standard library (for g++; not for OSX)-static-libgcc
: static linking of the GCC library (for gcc and g++; not for OSX)-static
: static linking of the winpthread library (for g++ mingw64)-pthread
: enable pthread support (not for Windows)-arch i386
: OSX: create 32bit x86 binaries-arch x86_64
: OSX: create 64bit x86 binaries-undefined dynamic_lookup
: required for Lua/C modules on OSX (don't link them to luajit!)-mmacosx-version-min=10.6
: for C++ modules on OSX: link to libstdc++.6 instead of the newer libc++.1-install_name @loader_path/<libname>.dylib
: for OSX, for libs that are binary dependencies to other libs
ar rcs ../../bin/<platform>/static/<libname>.a *.o
IMPORTANT: place the
-L
and-l
switches after the input files!
gcc -c -O2 lpeg.c -I. -I../lua
gcc -shared -s -static-libgcc -o ../../bin/linux32/clib/lpeg.so
ar rcs ../../bin/linux32/static/liblpeg.so
In some cases it's going to be more complicated than that.
- sometimes you won't get away with compiling
*.c
-- some libraries rely on the makefile to choose the C files that need to be compiled for a specific platform or set of options (eg. [socket]) - some libraries actually do use one or two of the myriad of defines
generated by the
./configure
script -- you might have to grep for those and add appropriate-D
switches to the command line. - some libraries have parts written in assembler or other language. At that point, maybe a simple makefile is a better alternative.
- if the package has a clean and simple makefile that doesn't add more dependencies to the toolchain, use that.
The way you add modules to luapower.com is:
- first you make a git repo that resembles a luapower package
- then you can either:
- publish it on your server or github account (luapower users will clone from that url directly)
- I will add your package to the package database
- I will periodically pull and update luapower.com
- publish it and manage it yourself on luapower.com
- I will add you as an admin to the luapower github account (it's an organization account)
- you will update luapower.com yourself
- publish it on your server or github account (luapower users will clone from that url directly)
Before publishing a luapower module, please consider:
- what name you plan to use for your module
- how your module relates to other modules
Choosing a good name is important if you want people to find your module on luapower.com and understand (from the name alone) what it does. Likewise, it's a good idea to be sure that your module is doing something new or at least different (and hopefully better) than something already on luapower.com.
Ideally, your module has:
- distinction - focused problem domain
- completeness - exhaustive of the problem domain
- API documentation - so it can be integrated into luapower.com
- test and/or demo - so it can be seen to work
- a non-viral license - so it doesn't impose restrictions on other modules
Of course, few modules (in any language) qualify on all fronts, so luapower.com is inevitably an ecclectic mix. In any case, if your module collection is too specialized to be added to luapower.com or you simply don't want to mix it in, here's where you can have your cake and eat it too.
Luapower can be easily forked and used as a personal website for publishing luapower modules.
Luapower is composed of:
- a static website generated with pandoc templating
- a Lua script for updating the package database, navigation tree, and dependency lists offline
- a few simple shell scripts for working with git in a shared-work-tree environment
Which means that with a few forks and a few tweaks you can have your own luapower clone with your own modules on it. The only dependency is pandoc for generating the website.
This is a powerful command that extracts and aggregates data from the luapower environment and gives
detailed information about packages, modules and documentation. It can give accurate information about dependencies
between modules and packages because it actually loads the module and tracks require
calls, and then it
integrates that information with the information about packages.
It is also used for generating the package database on luapower.com, along with the the dependency lists you see on each module's page.
The luapower
command is a Lua script that depends on [luajit], [lfs], [glue] and [tuple] so let's clone these first:
> clone luajit
> clone lfs
> clone glue
> clone tuple
For updating the website, we also need to clone its files in the _site
sub-directory:
> git clone https://github.com/luapower/luapower.github.io _site
The rest you can learn from the tool itself:
> luapower
USAGE: luapower <command> ...
HELP
help this screen
PACKAGES
packages list installed packages
known list all known package
left list not yet installed packages
PACKAGE INFO
describe <package> describe a package
type [package] package type
ver [package] current git version
tags [package] git tags
tag [package] current git tag
files [package] tracked files
docs [package] docs
modules [package] modules
scripts [package] scripts
mtree [package] module tree
mtags [package [module]] module info
platforms [package] supported platforms
ctags [package] C package info
CHECKS
check [package] consistency checks
trackable trackable files
multitracked files tracked by multiple packages
untracked files not tracked by any package
DATABASE
update-db [package] update _site/packages.json
update-toc [package] update _site/toc.md
update [package] update both _site/packages.json and _site/toc.md
rebuild-db rebuild _site/packages.json
DEPENDENCIES
requires <module> direct module requires
rall <module> direct and indirect module requires
rtree <module> module require log tree
rext <module> direct-external module requires
pall <module> direct and indirect package dependencies
pext <module> direct-external package dependencies
ppall [package] direct and indirect package dependencies
ppext [package] direct-external package dependencies
cdeps [package] direct and indirect C dependencies
rrev <module> all modules that require a module
The `package` arg defaults to the env var PROJECT, as set by the `proj` command,
and if that is not set, it defaults to `--all`, meaning all packages.
Look into _site/config.js
for what needs to be adjusted.