mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2025-12-06 02:40:26 -08:00
examples: add cmake example
This commit is contained in:
parent
3b84b388b2
commit
4f392ddbe2
6 changed files with 229 additions and 0 deletions
58
examples/cmake/CMakeLists.txt
Normal file
58
examples/cmake/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#=============================================================================
|
||||
# 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/")
|
||||
|
||||
# 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)
|
||||
include_directories(${ECL_INCLUDE_DIR})
|
||||
|
||||
|
||||
# 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.
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/core-lisp.a
|
||||
COMMAND ${ECL_BIN_PATH} --norc
|
||||
--eval '(require :asdf)'
|
||||
# Remember to end path with / here. Notably ....src/lisp/, not ....src/lisp
|
||||
--eval '(push \"${CMAKE_CURRENT_SOURCE_DIR}/src/lisp/\" asdf:*central-registry*)'
|
||||
--eval '(asdf:make-build :core-lisp :type :static-library :move-here \"${CMAKE_CURRENT_BINARY_DIR}\" :init-name \"init_lib_CORE_LISP\")'
|
||||
--eval '(quit)'
|
||||
DEPENDS ${CORE_LISP_SOURCES})
|
||||
# This goes in pair with `add_custom_command` above.
|
||||
add_custom_target(core-lisp ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/core-lisp.a)
|
||||
|
||||
# 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)
|
||||
|
||||
# Make cmake_ecl depend on core-lisp so it's going to be build before executable
|
||||
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}/core-lisp.a)
|
||||
|
||||
set_target_properties(cmake_ecl PROPERTIES
|
||||
# Set c++ standard
|
||||
CXX_STANDARD 17
|
||||
# Do you want to use custom compiler extensions?
|
||||
CXX_EXTENSION ON)
|
||||
|
||||
72
examples/cmake/README.md
Normal file
72
examples/cmake/README.md
Normal file
|
|
@ -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.
|
||||
82
examples/cmake/cmake/Modules/FindECL.cmake
Normal file
82
examples/cmake/cmake/Modules/FindECL.cmake
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
#=============================================================================
|
||||
# FindECL
|
||||
# --------
|
||||
#
|
||||
# Find ECL library and binary executables.
|
||||
#
|
||||
# Find the Embedded Common Lisp library headers and libraries.
|
||||
#
|
||||
# This module provides the following variables:
|
||||
#
|
||||
# ECL_INCLUDE_DIRS - where to find ecl/ecl.h, etc.
|
||||
# ECL_LIBRARIES - List of libraries to link when using ecl.
|
||||
# ECL_FOUND - True if ecl found.
|
||||
# ECL_VERSION_STRING - the version of ecl found (since CMake 2.8.8)
|
||||
#
|
||||
# ECL_BIN_DIR - directory that contains `ecl` and `ecl-config` executables
|
||||
# ECL_BIN_PATH - path to `ecl` binary executable
|
||||
# ECL_CONFIG_BIN_PATH - path to `ecl-config` binary executable
|
||||
# ECL_VERSION - full version string e.g. "16.1.3"
|
||||
# ECL_VERSION_MAJOR - major version string e.g. "16"
|
||||
# ECL_VERSION_MINOR - minor version string e.g. "1"
|
||||
# ECL_VERSION_PATCH - patch version string e.g. "3"
|
||||
#=============================================================================
|
||||
find_path(ECL_INCLUDE_DIR NAMES ecl/ecl.h)
|
||||
mark_as_advanced(ECL_INCLUDE_DIR)
|
||||
|
||||
find_library(ECL_LIBRARY NAMES
|
||||
ecl
|
||||
# TODO check how it's on windows
|
||||
)
|
||||
mark_as_advanced(ECL_LIBRARY)
|
||||
|
||||
# Find the ECL_VERSION_STRING
|
||||
if(ECL_INCLUDE_DIR)
|
||||
if(EXISTS "${ECL_INCLUDE_DIR}/ecl/config.h")
|
||||
file(STRINGS "${ECL_INCLUDE_DIR}/ecl/config.h" ecl_version_str
|
||||
REGEX "^#define[\t ]+ECL_VERSION_NUMBER[\t ]+[0-9]*.*")
|
||||
|
||||
string(REGEX REPLACE "^#define[\t ]+ECL_VERSION_NUMBER[\t ]+([0-9]*).*"
|
||||
"\\1" ECL_VERSION_STR_RAW ${ecl_version_str})
|
||||
|
||||
# at this moment ${ECL_VERSION_STR_RAW} contain version number in format
|
||||
# 160103 for version 16.1.3. Let's convert it to period separated format.
|
||||
set(version_helper_regex "^([0-9][0-9])([0-9][0-9])([0-9][0-9])$")
|
||||
string(REGEX REPLACE ${version_helper_regex} "\\1" major_raw
|
||||
${ECL_VERSION_STR_RAW})
|
||||
string(REGEX REPLACE ${version_helper_regex} "\\2" minor_raw
|
||||
${ECL_VERSION_STR_RAW})
|
||||
string(REGEX REPLACE ${version_helper_regex} "\\3" patch_raw
|
||||
${ECL_VERSION_STR_RAW})
|
||||
|
||||
string(REGEX REPLACE "^[0]*([0-9]+)" "\\1" ECL_VERSION_MAJOR ${major_raw})
|
||||
string(REGEX REPLACE "^[0]*([0-9]+)" "\\1" ECL_VERSION_MINOR ${minor_raw})
|
||||
string(REGEX REPLACE "^[0]*([0-9]+)" "\\1" ECL_VERSION_PATCH ${patch_raw})
|
||||
# version format conversion is done
|
||||
|
||||
set(ECL_VERSION "${ECL_VERSION_MAJOR}.${ECL_VERSION_MINOR}.${ECL_VERSION_PATCH}")
|
||||
|
||||
unset(ecl_version_str)
|
||||
unset(ECL_VERSION_STR_RAW)
|
||||
unset(version_helper_regex)
|
||||
unset(major_raw)
|
||||
unset(minor_raw)
|
||||
unset(patch_raw)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_path(ECL_BIN_DIR bin/ecl)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(ECL
|
||||
REQUIRED_VARS ECL_LIBRARY ECL_INCLUDE_DIR
|
||||
VERSION_VAR ECL_VERSION_STRING)
|
||||
|
||||
if(ECL_FOUND)
|
||||
set(ECL_LIBRARIES ${ECL_LIBRARY})
|
||||
if(ECL_BIN_DIR)
|
||||
set(ECL_BIN_DIR "${ECL_BIN_DIR}/bin")
|
||||
set(ECL_BIN_PATH "${ECL_BIN_DIR}/ecl")
|
||||
set(ECL_CONFIG_BIN_PATH "${ECL_BIN_DIR}/ecl-config")
|
||||
endif()
|
||||
endif()
|
||||
14
examples/cmake/src/cxx/main.cpp
Normal file
14
examples/cmake/src/cxx/main.cpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#include <iostream>
|
||||
#include <ecl/ecl.h>
|
||||
|
||||
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;
|
||||
}
|
||||
2
examples/cmake/src/lisp/core-lisp.asd
Normal file
2
examples/cmake/src/lisp/core-lisp.asd
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
(defsystem "core-lisp"
|
||||
:components ((:file "core-lisp")))
|
||||
1
examples/cmake/src/lisp/core-lisp.lisp
Normal file
1
examples/cmake/src/lisp/core-lisp.lisp
Normal file
|
|
@ -0,0 +1 @@
|
|||
(defun hello-world () (format t "Hello World!~%"))
|
||||
Loading…
Add table
Add a link
Reference in a new issue