Browse Source

xmpp: add Common Lisp support library & integrate with cmake

- Like in danger-bird2, some Common Lisp gets compiled at weechat build
  time into a static library, which gets linked in to the final binary.
- This required some cmake trickery to get it to actually do the thing.
- As a proof of concept, we now get the "plugin loaded" message to be
  printed from Lisp, with the ECL version chucked in as a nifty trick.
master
eta 2 months ago
parent
commit
f6685b5106
  1. 4
      cmake/FindECL.cmake
  2. 16
      src/plugins/xmpp/CMakeLists.txt
  3. 14
      src/plugins/xmpp/compile.lisp
  4. 17
      src/plugins/xmpp/support.lisp
  5. 45
      src/plugins/xmpp/xmpp.c
  6. 7
      src/plugins/xmpp/xmpp.h

4
cmake/FindECL.cmake

@ -25,3 +25,7 @@ mark_as_advanced(ECL_INCLUDE_DIR ECL_LIBRARY )
set(ECL_LIBRARIES ${ECL_LIBRARY} )
set(ECL_INCLUDE_DIRS ${ECL_INCLUDE_DIR} )
### additions to the above
find_program(ECL_PROGRAM NAMES ecl REQUIRED)

16
src/plugins/xmpp/CMakeLists.txt

@ -23,6 +23,20 @@ set_target_properties(xmpp PROPERTIES PREFIX "")
include_directories(${ECL_INCLUDE_DIRS})
target_link_libraries(xmpp PkgConfig::LIBSTROPHE ${ECL_LIBRARY} coverage_config)
set(ECL_SUPPORT_LIB "${CMAKE_CURRENT_SOURCE_DIR}/libeclsupport.a")
add_custom_command(
OUTPUT ${ECL_SUPPORT_LIB}
COMMAND ${ECL_PROGRAM} ARGS -norc -load ${CMAKE_CURRENT_SOURCE_DIR}/compile.lisp -eval \"(cmpsupport \\\"${CMAKE_CURRENT_SOURCE_DIR}/support.lisp\\\" \\\"${ECL_SUPPORT_LIB}\\\")\"
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/support.lisp
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/compile.lisp
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Compiling Common Lisp support files"
)
add_custom_target(ecl_support DEPENDS ${ECL_SUPPORT_LIB})
add_dependencies(xmpp ecl_support)
target_link_libraries(xmpp PkgConfig::LIBSTROPHE ${ECL_LIBRARY} ${ECL_SUPPORT_LIB} coverage_config)
install(TARGETS xmpp LIBRARY DESTINATION ${WEECHAT_LIBDIR}/plugins)

14
src/plugins/xmpp/compile.lisp

@ -0,0 +1,14 @@
(require 'cmp)
(defun cmpsupport (source afile)
(let* ((src-length (length source))
;; HACK(eta): what the heck
(c::+static-library-format+ "~a.a")
(cursed-obj-file (concatenate 'string
(subseq source 0 (- src-length 4))
"o")))
(compile-file source :system-p t)
(c::build-static-library afile
:lisp-files (list cursed-obj-file)
:init-name "ecl_support_init")
(quit)))

17
src/plugins/xmpp/support.lisp

@ -0,0 +1,17 @@
(defpackage :wee-impl
(:use))
(defpackage :strophe-impl
(:use))
(defpackage :weexmpp
(:nicknames :wx)
(:use :cl))
(in-package :weexmpp)
(defun printf (format-string &rest args)
(wee-impl::printf nil (apply #'format nil format-string args)))
(defun initialize ()
(printf "xmpp: plugin loaded (ECL ~A)" (lisp-implementation-version)))

45
src/plugins/xmpp/xmpp.c

@ -255,7 +255,7 @@ xmpp_command_eval (const void *pointer, void *data,
return WEECHAT_RC_OK;
}
/*
void lisp_load(char *file)
{
ECL_HANDLER_CASE_BEGIN(ecl_process_env(), ecl_list1(ECL_T)) {
@ -266,7 +266,7 @@ void lisp_load(char *file)
weechat_printf(NULL, "%sxmpp: could not load Lisp %s: %s", weechat_prefix("error"), file, cond_fmt);
} ECL_HANDLER_CASE_END;
}
*/
void weechat_config_init() {
struct t_config_file *file = weechat_config_new("xmpp", NULL, NULL, NULL);
@ -315,6 +315,24 @@ int maybe_autoconnect(const void *data1, void *data, int remaining_calls) {
return WEECHAT_RC_OK;
}
cl_object clgc_printf(cl_object buffer, cl_object string) {
struct t_gui_buffer *buf = NULL;
if (buffer != ECL_NIL) {
buf = ecl_foreign_data_pointer_safe(buffer);
}
cl_object base = si_coerce_to_base_string(string);
char* message = base->base_string.self;
weechat_printf(buf, message);
return ECL_NIL;
}
void
init_ecl_functions()
{
cl_object package = ecl_find_package("WEE-IMPL");
assert(package != ECL_NIL);
ecl_def_c_function(_ecl_intern("PRINTF", package), clgc_printf, 2);
}
int weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char **argv) {
weechat_plugin = plugin;
@ -334,6 +352,9 @@ int weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char **argv)
// ...why does this even exist?
char **fake_argv = {"omg-wtf-bbq"};
cl_boot(0, fake_argv);
ecl_init_module(NULL, ecl_support_init);
init_ecl_functions();
cl_env_ptr env = ecl_process_env();
weechat_hook_command("cleval", "Evaluate a Common Lisp form", "[form]", "form: a Common Lisp form", "", &xmpp_command_eval, NULL, NULL);
weechat_hook_command("xconnect", "Connect to the XMPP server", "", "", "", &xmpp_command_connect, NULL, NULL);
@ -351,7 +372,25 @@ int weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char **argv)
return WEECHAT_RC_ERROR;
}
weechat_printf(NULL, "xmpp: plugin loaded");
cl_object package = ecl_find_package("WEEXMPP");
assert(package != ECL_NIL);
cl_object sym = _ecl_intern("INITIALIZE", package);
cl_object result = ECL_NIL;
int failed = 0;
ECL_HANDLER_CASE_BEGIN(env, ecl_list1(ECL_T)) {
cl_object func = cl_symbol_function(sym);
result = cl_funcall(1, func);
} ECL_HANDLER_CASE(1, condition) {
char* err = ecl_get_string_for(condition);
weechat_printf(NULL, "%sxmpp: failed to run Lisp initialize function: %s", weechat_prefix("error"), err);
failed = 1;
} ECL_HANDLER_CASE_END;
if (failed) {
return WEECHAT_RC_ERROR;
}
return WEECHAT_RC_OK;
}

7
src/plugins/xmpp/xmpp.h

@ -25,4 +25,11 @@
extern struct t_weechat_plugin *weechat_xmpp_plugin;
// from support.lisp
extern void ecl_support_init(cl_object);
#define ecls(x) ecl_make_simple_base_string(x,-1)
#define eclk(x) ecl_make_keyword(x)
#define eclcs(x) ecl_make_constant_base_string(x,-1)
#endif
Loading…
Cancel
Save