Commit 836141c9 authored by Vicent Marti's avatar Vicent Marti

lua: Setup compilation for the standalone tool

parent a833369b
......@@ -11,3 +11,4 @@ if(NOT PYTHON_ONLY)
add_subdirectory(cc)
endif()
add_subdirectory(python)
add_subdirectory(lua)
include(cmake/FindLuaJIT.cmake)
find_program(LUAJIT luajit)
FILE(GLOB_RECURSE SRC_LUA ${CMAKE_CURRENT_SOURCE_DIR}/bcc/*/*.lua)
ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/src/bcc.lua
COMMAND ${LUAJIT} src/squish.lua
DEPENDS ${SRC_LUA} ${CMAKE_CURRENT_SOURCE_DIR}/squishy
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/src/bcc.o
COMMAND ${LUAJIT} -bg src/bcc.lua src/bcc.o
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/bcc.lua
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
include_directories(${LUAJIT_INCLUDE_DIR})
add_executable(bcc-lua src/main.c src/bcc.o)
target_link_libraries(bcc-lua ${LUAJIT_LIBRARIES})
......@@ -98,4 +98,4 @@ int perf_reader_fd(struct perf_reader *reader);
void perf_reader_set_fd(struct perf_reader *reader, int fd);
]]
return rawget(_G, "BCC_STANDALONE") and ffi.C or ffi.load("bcc")
return ffi.load(rawget(_G, "LIBBCC_SO_PATH") or "bcc")
# Locate Lua library
# This module defines
# LUAJIT_FOUND, if false, do not try to link to Lua
# LUAJIT_LIBRARIES
# LUAJIT_INCLUDE_DIR, where to find lua.h
#
# Note that the expected include convention is
# #include "lua.h"
# and not
# #include <lua/lua.h>
# This is because, the lua location is not standardized and may exist
# in locations other than lua/
#=============================================================================
# Copyright 2007-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distributed this file outside of CMake, substitute the full
# License text for the above reference.)
#
# ################
# 2010 - modified for cronkite to find luajit instead of lua, as it was before.
#
FIND_PATH(LUAJIT_INCLUDE_DIR lua.h
HINTS
$ENV{LUAJIT_DIR}
PATH_SUFFIXES include/luajit-2.0 include/luajit2.0 include/luajit include
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local
/usr
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
)
FIND_LIBRARY(LUAJIT_LIBRARY
NAMES libluajit-51.a libluajit-5.1.a libluajit.a
HINTS
$ENV{LUAJIT_DIR}
PATH_SUFFIXES lib64 lib
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local
/usr
/sw
/opt/local
/opt/csw
/opt
)
IF(LUAJIT_LIBRARY)
IF(UNIX AND NOT APPLE)
FIND_LIBRARY(LUAJIT_MATH_LIBRARY m)
FIND_LIBRARY(LUAJIT_DL_LIBRARY dl)
SET( LUAJIT_LIBRARIES "${LUAJIT_LIBRARY};${LUAJIT_DL_LIBRARY};${LUAJIT_MATH_LIBRARY}" CACHE STRING "Lua Libraries")
ELSE(UNIX AND NOT APPLE)
SET( LUAJIT_LIBRARIES "${LUAJIT_LIBRARY}" CACHE STRING "Lua Libraries")
ENDIF(UNIX AND NOT APPLE)
ENDIF(LUAJIT_LIBRARY)
INCLUDE(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LUAJIT_FOUND to TRUE if
# all listed variables are TRUE
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LuaJIT DEFAULT_MSG LUAJIT_LIBRARIES LUAJIT_INCLUDE_DIR)
MARK_AS_ADVANCED(LUAJIT_INCLUDE_DIR LUAJIT_LIBRARIES LUAJIT_LIBRARY LUAJIT_MATH_LIBRARY)
Module "bcc.vendor.argparse" "bcc/vendor/argparse.lua"
Module "bcc.vendor.posix" "bcc/vendor/posix.lua"
Module "bcc.vendor.middleclass" "bcc/vendor/middleclass.lua"
Module "bcc.vendor.json" "bcc/vendor/json.lua"
Module "bcc.vendor.helpers" "bcc/vendor/helpers.lua"
Module "bcc.init" "bcc/init.lua"
Module "bcc.run" "bcc/run.lua"
Module "bcc.bpf" "bcc/bpf.lua"
Module "bcc.sym" "bcc/sym.lua"
Module "bcc.libbcc" "bcc/libbcc.lua"
Module "bcc.tracerpipe" "bcc/tracerpipe.lua"
Module "bcc.table" "bcc/table.lua"
Module "bcc.ld" "bcc/ld.lua"
Main "bcc/run.lua"
Output "src/bcc.lua"
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
static lua_State *globalL = NULL;
static const char *progname = NULL;
static void lstop (lua_State *L, lua_Debug *ar)
{
(void)ar; /* unused arg. */
lua_sethook(L, NULL, 0, 0);
luaL_error(L, "interrupted!");
}
static void laction (int i)
{
signal(i, SIG_DFL);
lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
}
static void l_message (const char *pname, const char *msg)
{
if (pname) fprintf(stderr, "%s: ", pname);
fprintf(stderr, "%s\n", msg);
fflush(stderr);
}
static int report(lua_State *L, int status)
{
if (status && !lua_isnil(L, -1)) {
const char *msg = lua_tostring(L, -1);
if (msg == NULL) msg = "(error object is not a string)";
l_message(progname, msg);
lua_pop(L, 1);
}
return status;
}
static int traceback (lua_State *L)
{
if (!lua_isstring(L, 1)) /* 'message' not a string? */
return 1; /* keep it intact */
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
if (!lua_istable(L, -1)) {
lua_pop(L, 1);
return 1;
}
lua_getfield(L, -1, "traceback");
if (!lua_isfunction(L, -1)) {
lua_pop(L, 2);
return 1;
}
lua_pushvalue(L, 1); /* pass error message */
lua_pushinteger(L, 2); /* skip this function and traceback */
lua_call(L, 2, 1); /* call debug.traceback */
return 1;
}
static int docall (lua_State *L, int narg, int clear)
{
int status;
int base = lua_gettop(L) - narg; /* function index */
lua_pushcfunction(L, traceback); /* push traceback function */
lua_insert(L, base); /* put it under chunk and args */
signal(SIGINT, laction);
status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
signal(SIGINT, SIG_DFL);
lua_remove(L, base); /* remove traceback function */
/* force a complete garbage collection in case of errors */
if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
return status;
}
static int dolibrary (lua_State *L, const char *name, int clear)
{
lua_getglobal(L, "require");
lua_pushstring(L, name);
return report(L, docall(L, 1, clear));
}
struct Smain {
int argc;
char **argv;
int status;
};
static void pushargv(lua_State *L, char **argv, int argc, int offset)
{
int i, j;
lua_createtable(L, argc, 0);
for (i = offset, j = 1; i < argc; i++, j++) {
lua_pushstring(L, argv[i]);
lua_rawseti(L, -2, j);
}
}
static int find_libbcc(lua_State *L)
{
const char *libbcc = getenv("LIBBCC_SO_PATH");
char buffer[4096];
if (libbcc == NULL) {
char *dirname;
if (readlink("/proc/self/exe", buffer, sizeof(buffer)) < 0)
return -1;
dirname = strrchr(buffer, '/');
if (dirname == NULL)
return -1;
strcpy(dirname + 1, "libbcc.so");
libbcc = buffer;
}
if (access(libbcc, F_OK|R_OK|X_OK) != 0)
return -1;
lua_pushstring(L, libbcc);
lua_setglobal(L, "LIBBCC_SO_PATH");
return 0;
}
static int pmain(lua_State *L)
{
struct Smain *s = (struct Smain *)lua_touserdata(L, 1);
globalL = L;
lua_gc(L, LUA_GCSTOP, 0);
luaL_openlibs(L);
lua_gc(L, LUA_GCRESTART, 0);
if (find_libbcc(L) < 0) {
s->status = 1;
l_message(progname, "failed to find libbcc.so");
return 0;
}
s->status = dolibrary(L, "bcc", 0);
if (s->status)
return 0;
lua_pushboolean(L, 1);
lua_setglobal(L, "BCC_STANDALONE");
pushargv(L, s->argv, s->argc, 1);
lua_setglobal(L, "arg");
s->status = report(L, docall(L, 0, 1));
return 0;
}
int main (int argc, char **argv)
{
int status;
struct Smain s;
lua_State *L = lua_open(); /* create state */
if (L == NULL) {
l_message(argv[0], "cannot create state: not enough memory");
return EXIT_FAILURE;
}
if (argc < 2) {
fprintf(stderr, "usage: %s path_to_probe.lua [...]\n", argv[0]);
return EXIT_FAILURE;
}
progname = argv[0];
s.argc = argc;
s.argv = argv;
s.status = 0;
status = lua_cpcall(L, &pmain, &s);
report(L, status);
lua_close(L);
return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
}
#!/usr/bin/env lua
local short_opts = { v = "verbose", vv = "very_verbose", o = "output", q = "quiet", qq = "very_quiet", g = "debug" }
local opts = { use_http = false };
for _, opt in ipairs(arg) do
if opt:match("^%-") then
local name = opt:match("^%-%-?([^%s=]+)()")
name = (short_opts[name] or name):gsub("%-+", "_");
if name:match("^no_") then
name = name:sub(4, -1);
opts[name] = false;
else
opts[name] = opt:match("=(.*)$") or true;
end
else
base_path = opt;
end
end
if opts.very_verbose then opts.verbose = true; end
if opts.very_quiet then opts.quiet = true; end
local noprint = function () end
local print_err, print_info, print_verbose, print_debug = noprint, noprint, noprint, noprint;
if not opts.very_quiet then print_err = print; end
if not opts.quiet then print_info = print; end
if opts.verbose or opts.very_verbose then print_verbose = print; end
if opts.very_verbose then print_debug = print; end
print = print_verbose;
local modules, main_files, resources = {}, {}, {};
-- Functions to be called from squishy file --
function Module(name)
if modules[name] then
print_verbose("Ignoring duplicate module definition for "..name);
return function () end
end
local i = #modules+1;
modules[i] = { name = name, url = ___fetch_url };
modules[name] = modules[i];
return function (path)
modules[i].path = path;
end
end
function Resource(name, path)
local i = #resources+1;
resources[i] = { name = name, path = path or name };
return function (path)
resources[i].path = path;
end
end
function AutoFetchURL(url)
___fetch_url = url;
end
function Main(fn)
table.insert(main_files, fn);
end
function Output(fn)
if opts.output == nil then
out_fn = fn;
end
end
function Option(name)
name = name:gsub("%-", "_");
if opts[name] == nil then
opts[name] = true;
return function (value)
opts[name] = value;
end
else
return function () end;
end
end
function GetOption(name)
return opts[name:gsub('%-', '_')];
end
function Message(message)
if not opts.quiet then
print_info(message);
end
end
function Error(message)
if not opts.very_quiet then
print_err(message);
end
end
function Exit()
os.exit(1);
end
-- -- -- -- -- -- -- --- -- -- -- -- -- -- -- --
base_path = (base_path or "."):gsub("/$", "").."/"
squishy_file = base_path .. "squishy";
out_fn = opts.output;
local ok, err = pcall(dofile, squishy_file);
if not ok then
print_err("Couldn't read squishy file: "..err);
os.exit(1);
end
if not out_fn then
print_err("No output file specified by user or squishy file");
os.exit(1);
elseif #main_files == 0 and #modules == 0 and #resources == 0 then
print_err("No files, modules or resources. Not going to generate an empty file.");
os.exit(1);
end
local fetch = {};
function fetch.filesystem(path)
local f, err = io.open(path);
if not f then return false, err; end
local data = f:read("*a");
f:close();
return data;
end
if opts.use_http then
function fetch.http(url)
local http = require "socket.http";
local body, status = http.request(url);
if status == 200 then
return body;
end
return false, "HTTP status code: "..tostring(status);
end
else
function fetch.http(url)
return false, "Module not found. Re-squish with --use-http option to fetch it from "..url;
end
end
print_info("Writing "..out_fn.."...");
local f, err = io.open(out_fn, "w+");
if not f then
print_err("Couldn't open output file: "..tostring(err));
os.exit(1);
end
if opts.executable then
if opts.executable == true then
f:write("#!/usr/bin/env lua\n");
else
f:write(opts.executable, "\n");
end
end
if opts.debug then
f:write(require_resource("squish.debug"));
end
print_verbose("Resolving modules...");
do
local LUA_DIRSEP = package.config:sub(1,1);
local LUA_PATH_MARK = package.config:sub(5,5);
local package_path = package.path:gsub("[^;]+", function (path)
if not path:match("^%"..LUA_DIRSEP) then
return base_path..path;
end
end):gsub("/%./", "/");
local package_cpath = package.cpath:gsub("[^;]+", function (path)
if not path:match("^%"..LUA_DIRSEP) then
return base_path..path;
end
end):gsub("/%./", "/");
function resolve_module(name, path)
name = name:gsub("%.", LUA_DIRSEP);
for c in path:gmatch("[^;]+") do
c = c:gsub("%"..LUA_PATH_MARK, name);
print_debug("Looking for "..c)
local f = io.open(c);
if f then
print_debug("Found!");
f:close();
return c;
end
end
return nil; -- not found
end
for i, module in ipairs(modules) do
if not module.path then
module.path = resolve_module(module.name, package_path);
if not module.path then
print_err("Couldn't resolve module: "..module.name);
else
-- Strip base_path from resolved path
module.path = module.path:gsub("^"..base_path:gsub("%p", "%%%1"), "");
end
end
end
end
print_verbose("Packing modules...");
for _, module in ipairs(modules) do
local modulename, path = module.name, module.path;
if module.path:sub(1,1) ~= "/" then
path = base_path..module.path;
end
print_debug("Packing "..modulename.." ("..path..")...");
local data, err = fetch.filesystem(path);
if (not data) and module.url then
print_debug("Fetching: ".. module.url:gsub("%?", module.path))
data, err = fetch.http(module.url:gsub("%?", module.path));
end
if data then
f:write("package.preload['", modulename, "'] = (function (...)\n");
f:write(data);
f:write(" end)\n");
if opts.debug then
f:write(string.format("package.preload[%q] = ___adjust_chunk(package.preload[%q], %q);\n\n",
modulename, modulename, "@"..path));
end
else
print_err("Couldn't pack module '"..modulename.."': "..(err or "unknown error... path to module file correct?"));
os.exit(1);
end
end
if #resources > 0 then
print_verbose("Packing resources...")
f:write("do local resources = {};\n");
for _, resource in ipairs(resources) do
local name, path = resource.name, resource.path;
local res_file, err = io.open(base_path..path, "rb");
if not res_file then
print_err("Couldn't load resource: "..tostring(err));
os.exit(1);
end
local data = res_file:read("*a");
local maxequals = 0;
data:gsub("(=+)", function (equals_string) maxequals = math.max(maxequals, #equals_string); end);
f:write(("resources[%q] = %q"):format(name, data));
--[[ f:write(("resources[%q] = ["):format(name), string.rep("=", maxequals+1), "[");
f:write(data);
f:write("]", string.rep("=", maxequals+1), "];"); ]]
end
if opts.virtual_io then
local vio = require_resource("vio");
if not vio then
print_err("Virtual IO requested but is not enabled in this build of squish");
else
-- Insert vio library
f:write(vio, "\n")
-- Override standard functions to use vio if opening a resource
f:write[[local io_open, io_lines = io.open, io.lines; function io.open(fn, mode)
if not resources[fn] then
return io_open(fn, mode);
else
return vio.open(resources[fn]);
end end
function io.lines(fn)
if not resources[fn] then
return io_lines(fn);
else
return vio.open(resources[fn]):lines()
end end
local _dofile = dofile;
function dofile(fn)
if not resources[fn] then
return _dofile(fn);
else
return assert(loadstring(resources[fn]))();
end end
local _loadfile = loadfile;
function loadfile(fn)
if not resources[fn] then
return _loadfile(fn);
else
return loadstring(resources[fn], "@"..fn);
end end ]]
end
end
f:write[[function require_resource(name) return resources[name] or error("resource '"..tostring(name).."' not found"); end end ]]
end
print_debug("Finalising...")
for _, fn in pairs(main_files) do
local fin, err = io.open(base_path..fn);
if not fin then
print_err("Failed to open "..fn..": "..err);
os.exit(1);
else
f:write((fin:read("*a"):gsub("^#.-\n", "")));
fin:close();
end
end
f:close();
print_info("OK!");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment