Skip to content

Instantly share code, notes, and snippets.

@Reflexe
Created September 9, 2018 16:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Reflexe/b78962a67277cfbddf6dd5ad56f22e67 to your computer and use it in GitHub Desktop.
Save Reflexe/b78962a67277cfbddf6dd5ad56f22e67 to your computer and use it in GitHub Desktop.
#!/bin/env bash
# I don't know way, but without this line gcc start to compile stdout :\
exec 1>&2
set -x
# build the linux targets with {linux_headers_path}/build;
# compile it to the our Makefile's path and read
# our Makefile from stdin to make its path simpler.
# 'info' or 'compile'
mode=$1
makefile_path=$2
output_dirname=$3
output_filename="$name.ko"
make_mode=""
export sandbox_pwd=$PWD
if [[ "$mode" == "info" ]]; then
make_mode="zq_info"
elif [[ "$mode" == "compile" ]]; then
make_mode="zq_modules"
else
echo "Invalid mode: $mode" 1>&2
exit 1
fi
make_output=$(make -s -f "-" "$make_mode" < "$makefile_path" 2>&1)
if test $? -ne 0; then
echo "$make_output"
exit 1
fi
warnings=`grep 'WARNING:' <<< "$make_output"`
if test $? -eq 0; then
echo "Error: Found a warning: " 1>&2
echo "$warnings" 1>&2
exit 1
fi
if [[ "$mode" == "info" ]]; then
echo "$make_output"
else
# Then, copy the built target (X.ko) to the output directory.
cp -r "$(dirname "$makefile_path")/$output_filename" "$output_dirname"
fi
# @brief Escape @string from @chars_to_escape with @escape_char.
# @param string [str] A string to escape.
# @param chars_to_escape [iteratable] Items to escape from @a string.
# @param escape_char [str] Char to replace any occurence of anyone from
# @a chars_to_escape.
def escape(string, chars_to_escape, escape_char=None):
# Set the default escape_char.
if escape_char == None:
escape_char = '\\'
# Replace each occurence of @char with "@char+@escape_char".
for char in chars_to_escape:
string = string.replace (char, escape_char + char)
return string
# @brief UNIX: generate a relative path to the workspace root from a path within the workspace.
# @param file the file path.
def get_relative_file_path_to_workspace(file):
return '../' * file.path.count ('/')
# @brief Escape spaces from strings (paths)
#
# non-cross-platform way to escape spaces from strings.
# Especially useful for paths with spaces.
#
# @param A string to escape.
#
# @return 'A B C' -> 'A\ B\ C'
def escape_spaces(string):
return escape(string, (' '))
def _impl(ctx):
# Add env vars to the default env.
make_env_vars = ctx.configuration.default_shell_env
includes_files_depset = depset()
includes_paths_depset = depset()
for target in ctx.attr.includes:
includes_files_depset += target.files
includes_paths_depset += [file.dirname for file in target.files]
# Get the relative path from our makefile's dir to the workspace.
CppCore_to_workspace = get_relative_file_path_to_workspace (ctx.file._makefile)
# Get the module sources and add it the env var.
make_env_vars['ZQ_MODULE_SOURCES'] = ''
for f in ctx.files.srcs:
make_env_vars['ZQ_MODULE_SOURCES'] += escape_spaces(CppCore_to_workspace + f.path) + ' '
libs_depset = depset()
make_env_vars['ZQ_OBJECTS'] = ''
for dep in ctx.attr.deps:
if 'cc' in dir(dep):
libs_depset += dep.cc.libs
includes_paths_depset += dep.cc.system_include_directories
includes_files_depset += dep.cc.transitive_headers
for object in libs_depset.to_list()[::-1]:
make_env_vars['ZQ_OBJECTS'] += escape_spaces(CppCore_to_workspace + object.path) + ' '
# Set the target's name.
make_env_vars['name'] = ctx.attr.name
# Set the header's path.
#linux_headers_path_to_workspace = get_relative_file_path_to_workspace (ctx.file.linux_headers_path)
make_env_vars['ZQ_LINUX_HEADERS_PATH'] = escape_spaces(ctx.file.linux_headers_path.path)
make_env_vars['ZQ_MAKEFILE_PATH'] = escape_spaces(ctx.file._makefile.dirname)
# Add includes as compiler arguments.
make_env_vars['ZQ_INCLUDE_PATHS'] = ''
for d in includes_paths_depset.to_list():
make_env_vars['ZQ_INCLUDE_PATHS'] += escape_spaces(d) + ' '
# Run the actual action.
ctx.actions.run(
inputs=ctx.files.srcs
+ ctx.files._makefile
+ ctx.files.linux_headers_path
+ ctx.files.deps
+ includes_files_depset.to_list()
+ libs_depset.to_list(),
outputs=[ctx.outputs._output_ko],
executable=ctx.file._script,
arguments=['compile',
ctx.file._makefile.path,
ctx.outputs._output_ko.path],
progress_message= "Compiling and linking Linux Module: %s" % ctx.attr.name,
env = make_env_vars)
linux_module = rule(
implementation=_impl,
attrs={
'_script': attr.label(default=Label(':CompileLinuxModule.sh'),
allow_single_file=True),
'_makefile': attr.label(default=Label(':Makefile'),
allow_single_file=True),
'srcs': attr.label_list(allow_files=True),
'linux_headers_path': attr.label(
allow_single_file=True),
'deps': attr.label_list(),
'includes': attr.label_list(allow_files=True),
},
# The output .ko file. Maybe we should also save the .o files?
outputs={"_output_ko": "%{name}.ko"},
)
ZQ_LINUX_MODULE_OBJECT := $(addsuffix .o,$(basename $(ZQ_MODULE_SOURCES)))
OTHER_MODULE_OBJECTS=$(filter-out Linux.o,$(ZQ_LINUX_MODULE_OBJECT))
name := $(name)
obj-m := $(name).o
ko-m := $(name).ko
$(name)-objs := $(OTHER_MODULE_OBJECTS) $(ZQ_OBJECTS)
ccflags-y := $(addprefix -I${sandbox_pwd}/, $(ZQ_INCLUDE_PATHS))
zq_info : ; make -s -C "${ZQ_LINUX_HEADERS_PATH}" M="${sandbox_pwd}/${ZQ_MAKEFILE_PATH}" -k --no-print-directory --eval='$$(info $$(KBUILD_CFLAGS))'
zq_modules : ; make -C "${sandbox_pwd}/${ZQ_LINUX_HEADERS_PATH}" M="${sandbox_pwd}/${ZQ_MAKEFILE_PATH}" modules
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment