diff --git a/examples/cmake-win/CMakeLists.txt b/examples/cmake-win/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..85143e177c665a841f72bc96804af2ae757f10cc --- /dev/null +++ b/examples/cmake-win/CMakeLists.txt @@ -0,0 +1,80 @@ +#============================================================================= +# CMake project configuration file. +# Documentation: https://cmake.org/cmake/help/v3.6/ +#============================================================================= +cmake_minimum_required(VERSION 3.6) # released in 2016 +project(cmake_ecl_proj) +set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_SOURCE_DIR}/cmake/Modules/") + +set(ECL_LIBRARY_DIR ${ECL_DIR}) +set(RESULT_CORE_LISP_LIB core-lisp.lib) +######### +set(ECL_INCLUDE_DIR ${ECL_LIBRARY_DIR}) +set(ECL_BIN_PATH ${ECL_LIBRARY_DIR}/ecl.exe) +set(ECL_LIBRARIES ecl.lib) + +set(ENV_DATA_FILE ${CMAKE_CURRENT_SOURCE_DIR}/tmp-env-data.txt) +set(FIX_BUILD_LISP ${CMAKE_CURRENT_SOURCE_DIR}/fix-build.lisp) +set(SAVE_ARG_BAT ${CMAKE_CURRENT_SOURCE_DIR}/save-arg.bat) + +#set(CMAKE_EXE_LINKER_FLAGS ecl) + +include_directories(${ECL_INCLUDE_DIR}) +link_directories(${ECL_LIBRARY_DIR}) + +# Find ECL library. Refer to ./cmake/Modules/FindECL.cmake and +# https://cmake.org/cmake/help/v3.0/command/find_package.html +find_package(ECL REQUIRED) + +# Put lisp sources and other files relevant for compilation here +# Any change of that files will trigger recompilation of `core-lisp` target +set(CORE_LISP_SOURCES + src/lisp/core-lisp.asd + src/lisp/core-lisp.lisp) + +# Specify how `core-lisp` library is build by ECL +# The library is going to be built statically and moved to +# ${CMAKE_CURRENT_BINARY_DIR}. + +# How to customize +# ================ +# You can change "core-lisp" consistently to different name. +# Value of `:init-name` keyword must match extern declaration in C++ code. + +# Remember to end path with / here. Notably ....src/lisp/, not ....src/lisp +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${RESULT_CORE_LISP_LIB} + COMMAND ${SAVE_ARG_BAT} new ${ENV_DATA_FILE} + COMMAND ${SAVE_ARG_BAT} add ${ENV_DATA_FILE} CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND ${SAVE_ARG_BAT} add ${ENV_DATA_FILE} CMAKE_CURRENT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${SAVE_ARG_BAT} add ${ENV_DATA_FILE} CMAKE_CUR_DIR_WITH_LISP ${CMAKE_CURRENT_SOURCE_DIR}/src/lisp/ + COMMAND ${SAVE_ARG_BAT} add ${ENV_DATA_FILE} init_lib_CORE_LISP init_lib_CORE_LISP + COMMAND ${ECL_BIN_PATH} --norc --load "${FIX_BUILD_LISP}" + DEPENDS ${CORE_LISP_SOURCES} +) + +# This goes in pair with `add_custom_command` above. +add_custom_target(core-lisp ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${RESULT_CORE_LISP_LIB}) + +#add_custom_target(ecl_lib "ecl.lib") + +# Define executable to build. You can add other sources here. +# You may change "cmake_ecl" consistently into any name. +add_executable(cmake_ecl + src/cxx/main.cpp) + +#add_library(ecl_lib STATIC IMPORTED "ecl.lib") +# Make cmake_ecl depend on core-lisp so it's going to be build before executable +#add_dependencies(cmake_ecl core-lisp ecl_lib) +add_dependencies(cmake_ecl core-lisp) + +# Set what should be linked into `cmake_ecl` executable. +target_link_libraries(cmake_ecl + ${ECL_LIBRARIES} + ${CMAKE_CURRENT_BINARY_DIR}/${RESULT_CORE_LISP_LIB} + ecl) + +set_target_properties(cmake_ecl PROPERTIES + # Set c++ standard + CXX_STANDARD 17 + # Do you want to use custom compiler extensions? + CXX_EXTENSION ON) diff --git a/examples/cmake-win/README.md b/examples/cmake-win/README.md new file mode 100644 index 0000000000000000000000000000000000000000..75431ad592238bb27149b82f15113d64dddde0b0 --- /dev/null +++ b/examples/cmake-win/README.md @@ -0,0 +1,72 @@ +# Description +This example shows how to setup CMake to build C++ project which uses ECL library. + +In `src/lisp` is definition of `core-lisp` system that's being loaded into C++ +program. + +Functions defined in `src/lisp/core-lisp.lisp`: +``` +(defun hello-world () (format t "Hello World!~%")) +``` +are used in `src/cxx/main.cpp`: +``` +extern "C" { + extern void init_lib_CORE_LISP(cl_object); +} + +int main(int argc, char** argv) { + cl_boot(argc, argv); + ecl_init_module(NULL, init_lib_CORE_LISP); + cl_eval(c_string_to_object("(hello-world)")); + cl_shutdown(); + return 0; +} +``` + +## CMakeLists.txt +For more information about setup read `CMakeLists.txt` comments. + +# Build +Run: +``` +$ mkdir build +$ cd build +``` +If ECL is built and installed with non-default prefix use: + +``` +$ cmake -DCMAKE_PREFIX_PATH=/home/user/local_prefix/ .. +``` + +Otherwise you don't have to set `CMAKE_PREFIX_PATH`: +``` +$ cmake .. +``` + +Finally run: +``` +$ make +``` + +It shall produce: `cmake_ecl` executable and `core-lisp.a` static library that +has been linked to executable. + + +# Run +``` +$ ./cmake_ecl +Hello World! +``` + +# Notes + 1. You don't have to remove `./build` directory if you want to change option + in `CMakeLists.txt`. Just run `make`. + + 2. If you see `undefined reference` errors look at `nm --demangle core-lisp.a` + output. You may have forgot setting `:init-name` in `CMakeLists.txt` + + 3. To reuse this example you must copy `cmake` directory to your project. It + contains `FindECL.cmake` + + 4. You don't have to have `ecl` executable in `$PATH` environment variable. + `FindECL.cmake` shall find it. diff --git a/examples/cmake-win/fix-build.lisp b/examples/cmake-win/fix-build.lisp new file mode 100644 index 0000000000000000000000000000000000000000..76c1137975b8b5287f87636855367c02299e3852 --- /dev/null +++ b/examples/cmake-win/fix-build.lisp @@ -0,0 +1,67 @@ +(in-package :cl-user) + +(require 'asdf) +(require 'cmp) +(require 'uiop) + +;(setf *load-pathname* nil) // Change it (but comment) for debugging +(progn +(defparameter *name-generated* "tmp-env-data.txt") +(defparameter *this-dir* (make-pathname :defaults *load-pathname* :name nil :type nil)) +(defparameter *path-generated* (merge-pathnames *name-generated* *this-dir*)) + +(format t "~%============== Reading cmake environment ===============~%") + +(defparameter *lines* nil) + +(defun split (str) + (uiop/utility:split-string str)) + +(defun clean (list) + (remove-if (lambda (elt) (or + (string= "" elt) + (string= " +" elt) + )) + list)) + +(progn + (setf *lines* nil) + (with-open-file (s *path-generated*) + (loop + :with is-first = t + :for line = (read-line s nil) + :while line + :do (if (not is-first) + (push (clean (split line)) *lines*) + (setf is-first nil) + )) + *lines*)) + +(defun get-var (name) + (second (assoc name *lines* :test 'string=))) + +;;Example: +;;(get-var "CMAKE_CURRENT_BINARY_DIR") + +(format t "build-env: ~s" *lines*) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(format t "~%============== Building ===============~%") + +;;Remember to end path with / here. Notably ....src/lisp/, not ....src/lisp ; +(push (get-var "CMAKE_CUR_DIR_WITH_LISP") asdf:*central-registry*) +(print "===================") +(print asdf:*central-registry*) +(print "===================") + +(asdf:load-system :core-lisp) +) + + +(asdf:make-build :core-lisp + :type :static-library + :move-here (get-var "CMAKE_CURRENT_BINARY_DIR") + :init-name (get-var "init_lib_CORE_LISP")) + + diff --git a/examples/cmake-win/generate.bat b/examples/cmake-win/generate.bat new file mode 100644 index 0000000000000000000000000000000000000000..5f4ec726e32d1772caa17c6e2af45a4de9209b7f --- /dev/null +++ b/examples/cmake-win/generate.bat @@ -0,0 +1 @@ +cmake -DECL_DIR=%1 -DECL_LIBRARY=ecl.lib -DECL_INCLUDE_DIR=%1\ecl .. diff --git a/examples/cmake-win/save-arg.bat b/examples/cmake-win/save-arg.bat new file mode 100644 index 0000000000000000000000000000000000000000..7cc0c69a1e93ac5f30e4f4b17f466d5d7431ddf1 --- /dev/null +++ b/examples/cmake-win/save-arg.bat @@ -0,0 +1,15 @@ +@echo off +set cmd=%1 +set file=%2 +set data=%3 +set data2=%4 + +echo ============================ +echo cmd: %cmd% +echo file: %file% +echo data: %data% +echo data2: %data2% +echo ============================= + +if "%cmd%" == "new" echo "REM Auto generated. Here variables for build program" > "%file%" +if "%cmd%" == "add" echo %data% %data2% >> "%file%" \ No newline at end of file diff --git a/examples/cmake-win/src/lisp/core-lisp.asd b/examples/cmake-win/src/lisp/core-lisp.asd new file mode 100644 index 0000000000000000000000000000000000000000..9a288890532e5d95c6c3782445dadfa50dc0ae5d --- /dev/null +++ b/examples/cmake-win/src/lisp/core-lisp.asd @@ -0,0 +1,2 @@ +(defsystem "core-lisp" + :components ((:file "core-lisp"))) diff --git a/examples/cmake-win/src/lisp/core-lisp.lisp b/examples/cmake-win/src/lisp/core-lisp.lisp new file mode 100644 index 0000000000000000000000000000000000000000..931fa9dbed3ebb94fae463396ec096a178065df6 --- /dev/null +++ b/examples/cmake-win/src/lisp/core-lisp.lisp @@ -0,0 +1 @@ +(defun hello-world () (format t "Hello World!~%")) diff --git a/examples/cmake-win/tmp-env-data.txt b/examples/cmake-win/tmp-env-data.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/examples/cmake-win/tmp-env-data.txt @@ -0,0 +1 @@ +