Skip to content

Commit

Permalink
Add example of making C libraries in a test
Browse files Browse the repository at this point in the history
  • Loading branch information
edubart committed Sep 25, 2020
1 parent 4539446 commit 1c1062a
Show file tree
Hide file tree
Showing 12 changed files with 91 additions and 18 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ neluacfg.lua
.neluacfg.lua
/play
nelua-lua
/pkg
/pkg
/mylib_test
8 changes: 6 additions & 2 deletions nelua/analyzer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,8 @@ function visitors.Annotation(context, node, symbol)
if objattr._type then
objattr:update_fields()
end
elseif name == 'codename' then
objattr.fixedcodename = params
end

node.done = true
Expand Down Expand Up @@ -2163,8 +2165,10 @@ function visitors.FuncDef(context, node, polysymbol)
if context.entrypoint and context.entrypoint ~= node then
node:raisef("cannot have more than one function entrypoint")
end
attr.codename = attr.name
attr.declname = attr.name
if not attr.fixedcodename then
attr.codename = attr.name
end
attr.declname = attr.codename
context.entrypoint = node
end
end
Expand Down
14 changes: 7 additions & 7 deletions nelua/ccompiler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -134,32 +134,32 @@ local function detect_binary_extension(ccinfo, cflags)
if cflags:find('-shared') then
return '.dll'
else
return '.exe'
return '.exe', true
end
else
if cflags:find('-shared') then
return '.so'
else
return ''
return '', true
end
end
--luacov:enable
end


function compiler.compile_binary(cfile, outfile, compileopts)
local cflags = get_compiler_cflags(compileopts)
local ccinfo = compiler.get_cc_info()
local binext = detect_binary_extension(ccinfo, cflags)
local binfile = outfile .. binext
local binext, isexe = detect_binary_extension(ccinfo, cflags)
local binfile = outfile
if not stringer.endswith(binfile, binext) then binfile = binfile .. binext end

-- if the file with that hash already exists skip recompiling it
if not config.no_cache then
local cfile_mtime = fs.getmodtime(cfile)
local binfile_mtime = fs.getmodtime(binfile)
if cfile_mtime and binfile_mtime and cfile_mtime <= binfile_mtime then
if not config.quiet then console.info("using cached binary " .. binfile) end
return binfile
return binfile, isexe
end
end

Expand All @@ -178,7 +178,7 @@ function compiler.compile_binary(cfile, outfile, compileopts)
io.stderr:write(stderr)
end

return binfile
return binfile, isexe
end

function compiler.get_gdb_version() --luacov:disable
Expand Down
2 changes: 1 addition & 1 deletion nelua/cgenerator.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1464,7 +1464,7 @@ local function emit_main(ast, context)
mainemitter:add_ln("}")
mainemitter:dec_indent()

context:add_declaration('int nelua_main(int nelua_argc, char** nelua_argv);\n')
context:add_declaration('static int nelua_main(int nelua_argc, char** nelua_argv);\n')
else
mainemitter:inc_indent()
mainemitter:add_traversal(ast)
Expand Down
2 changes: 1 addition & 1 deletion nelua/configer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ local function create_parser(args)
local argparser = argparse("nelua", "Nelua 0.1")
argparser:flag('-c --compile', "Compile the generated code only", defconfig.compile)
argparser:flag('-b --compile-binary', "Compile the generated code and binaries only", defconfig.compile_binary)
--argparser:option('-o --output', "Output file when compiling")
argparser:flag('-e --eval', 'Evaluate string code from input', defconfig.eval)
argparser:flag('-l --lint', 'Only check syntax errors', defconfig.lint)
argparser:flag('-q --quiet', "Don't print any information while compiling", defconfig.quiet)
Expand All @@ -102,6 +101,7 @@ local function create_parser(args)
argparser:flag('-d --debug', 'Run through GDB to get crash backtraces', defconfig.debug)
argparser:flag('--no-cache', "Don't use any cached compilation", defconfig.no_cache)
argparser:flag('--no-color', 'Disable colorized output in the terminal.', defconfig.no_color)
argparser:option('-o --output', 'Copy output file to desired path.')
argparser:option('-D --define', 'Define values in the preprocessor')
:count("*"):convert(convert_param, tabler.copy(defconfig.define or {}))
argparser:option('-P --pragma', 'Set initial compiler pragma')
Expand Down
2 changes: 1 addition & 1 deletion nelua/luacompiler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function lua_compiler.compile_code(luacode, outfile)
end

function lua_compiler.compile_binary(luafile)
return luafile
return luafile, true
end

function lua_compiler.get_run_command(binaryfile, runargs)
Expand Down
13 changes: 9 additions & 4 deletions nelua/runner.lua
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,10 @@ local function run(argv, redirect)
if not infile then infile = 'eval_' .. stringer.hash(code) end

-- save the generated code
local outcachefile = fs.getcachepath(infile, config.cache_dir)
local outcacheprefix = fs.getcachepath(infile, config.cache_dir)
local outfile = config.output or outcacheprefix
local compiler = generator.compiler
local sourcefile = compiler.compile_code(code, outcachefile, compileopts)
local sourcefile = compiler.compile_code(code, outcacheprefix, compileopts)

if config.timing then
console.debugf('compile code %.1f ms', timer:elapsedrestart())
Expand All @@ -117,10 +118,14 @@ local function run(argv, redirect)
local dobinarycompile = config.compile_binary or dorun

-- compile the generated code
local binaryfile
local binaryfile, isexe
if dobinarycompile then
binaryfile = compiler.compile_binary(sourcefile, outcachefile, compileopts)
binaryfile, isexe = compiler.compile_binary(sourcefile, outfile, compileopts)

if not isexe then
if not config.quiet then console.info('library compiled!') end
return 0
end
if config.timing then
console.debugf('compile binary %.1f ms', timer:elapsedrestart())
end
Expand Down
2 changes: 2 additions & 0 deletions nelua/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ Type.shape = shaper.shape {
nickname = shaper.string:is_optional(),
-- The actual name of the type used in the code generator when emitting C code.
codename = shaper.string,
-- Fixed custom codename used in <codename> annotation.
fixedcodename = shaper.string:is_optional(),
-- Symbol that defined the type, not applicable for primitive types.
symbol = shaper.symbol:is_optional(),
-- Node that defined the type.
Expand Down
12 changes: 12 additions & 0 deletions spec/08-runner_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,16 @@ it("program arguments", function()
]], 'a', 'b', 'c'})
end)

it("C libraries", function()
assert.run({'-o', 'libmylib', 'tests/libmylib.nelua'})
assert.run({'-o', 'mylib_test', 'tests/mylib_test.nelua'}, [[mylib - init
mylib - in top scope
mylib - sum
the sum is:
3
mylib - terminate]])
os.remove('libmylib.so')
os.remove('mylib_test')
end)

end)
31 changes: 31 additions & 0 deletions tests/libmylib.nelua
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
-- Disable the garbage collector,
-- because libraries should not and cannot use the garbage collector,
-- this means that you are responsible to manually manage the memory.
## pragmas.nogc = true
-- Prefix used when declaring C symbols for this file.
-- With this an exported function named 'sum' will be exported as 'mylib_sum'
## pragmas.unitname = 'mylib'
-- Compilation flags needed for compiling C libraries.
## cflags '-shared -fPIC'

print 'mylib - in top scope'

local function sum(x: integer, y: integer): integer <cexport>
print 'mylib - sum'
return x + y
end

-- Initialize the library.
-- This function is marked as entry point, initialization code should be done here.
local function init() <entrypoint, codename 'mylib_init'>
-- Import and call nelua_main on initialization.
-- This function run all code in top scope and initializes global variables.
local function nelua_main(argc: cint, argv: *cstring): cint <cimport,nodecl> end
print 'mylib - init'
nelua_main(0, nilptr)
end

-- Terminate the library.
local function terminate() <cexport>
print 'mylib - terminate'
end
18 changes: 18 additions & 0 deletions tests/mylib_test.nelua
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
-- Add the current folder to the linker's library search path,
-- we expect that 'mylib' library is available in the current path.
## cflags "-L. -Wl,-rpath,'$ORIGIN'"
-- Link mylib C library.
## linklib 'mylib'

-- Import mylib functions.
local function mylib_sum(x: integer, y: integer): integer <cimport> end
local function mylib_init() <cimport> end
local function mylib_terminate() <cimport> end

-- Run example.
mylib_init()
local a = mylib_sum(1, 2)
print('the sum is:')
print(a)
assert(a == 3)
mylib_terminate()
2 changes: 1 addition & 1 deletion tools/covreporter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ local function report_coverage(reportfile)
body <- {| sfile* |} summary
sfile <- {| {:name: '' -> 'file' :} '='+%s+!'Summary'{:file: [-/_.%w]+ :}%s+'='+%nl (miss / sline / eline)* |}
miss <- !div '*'+'0 '{[^%nl]+} %nl
sline <- !div ' '* %d* ' '* {''} [^%nl]+ %nl
sline <- !div ' '* %d* ' '* {''} [^%nl]* %nl
eline <- [ ]* {''} %nl
div <- '==='+%s+[-/_.%w]+%s+'==='+%nl
summary <- {| heading {| line+ |} footer |}
Expand Down

0 comments on commit 1c1062a

Please sign in to comment.