From 1e74750f790ce66480e72dd63fa8daf7f448a5eb Mon Sep 17 00:00:00 2001 From: Heath Mitchell Date: Fri, 21 Jul 2023 00:56:24 +0200 Subject: [PATCH] Initial commit --- .gitignore | 6 +++++ CMakeLists.txt | 53 +++++++++++++++++++++++++++++++++++++ README.md | 49 ++++++++++++++++++++++++++++++++++ cmake/FindLibExample.cmake | 47 ++++++++++++++++++++++++++++++++ giteapc.make | 25 +++++++++++++++++ include/example/add.h | 16 +++++++++++ include/example/config.h.in | 9 +++++++ include/example/version.h | 23 ++++++++++++++++ src/add.c | 6 +++++ src/version.c | 18 +++++++++++++ 10 files changed, 252 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 README.md create mode 100644 cmake/FindLibExample.cmake create mode 100644 giteapc.make create mode 100644 include/example/add.h create mode 100644 include/example/config.h.in create mode 100644 include/example/version.h create mode 100644 src/add.c create mode 100644 src/version.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..517db40 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# Build files +build-fx +build-cg + +# GiteaPC support +giteapc-config.make diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..60333db --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,53 @@ +# libexample: build system + +cmake_minimum_required(VERSION 3.16) +project(libexample VERSION 1.0 LANGUAGES C) + +# Libraries that libexample depends on +find_package(Gint 2.1 REQUIRED) + +# Turn include/example/config.h.in into a proper config.h where the @VAR@ have +# been replaced; this is how version numbers are maintained. libexample_VERSION +# is set to "1.0" by the project() command. +# Note that the input (config.h.in) is relative to the source dir, but the +# output (config.h) is in the build dir, so it doesn't pollute the Git repo. +configure_file(include/example/config.h.in include/example/config.h) + +# With the target name "example", the output file will be called "libexample.a" +# (by default). +add_library(example STATIC src/add.c src/version.c) + +# Find headers in the following directories: +# -> The include subfolder of the source +# -> The include subfolder of the build files (for config.h) +# This doesn't affect add-ins that *use* the library; flags for these are set +# in FindLibExample.cmake. +target_include_directories(example PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/include" + "${CMAKE_CURRENT_BINARY_DIR}/include") + +# After building, install the target (that is, libexample.a) in the fxSDK's +# sysroot which contains libraries for the calculator. +install(TARGETS example + DESTINATION "${FXSDK_LIB}") + +# Install the headers. The contents of our include folder are added to the +# fxSDK's sysroot folder for headers. Since our headers are in an "example" +# subfolder, they will end up in ${FXSDK_INCLUDE}/example and users can include +# them as . +# +# Note the / at the end of the source DIRECTORY, which indicates to copy the +# *contents* of include/ at the destination, not the folder itself. +# +# We only install files called "*.h" to exclude config.h.in. +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/" + DESTINATION "${FXSDK_INCLUDE}" + FILES_MATCHING PATTERN "*.h") + +# Similarly, install config.h from the build dir. +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/include/example/config.h" + DESTINATION "${FXSDK_INCLUDE}/example") + +# Install FindLibExample.cmake so that users can do find_package(LibExample). +install(FILES cmake/FindLibExample.cmake + DESTINATION "${FXSDK_CMAKE_MODULE_PATH}") diff --git a/README.md b/README.md new file mode 100644 index 0000000..3d4db77 --- /dev/null +++ b/README.md @@ -0,0 +1,49 @@ +# libexample: A template gint library using CMake + +This repository is a (Gitea template) example of how to build a library to use with [gint](/Lephenixnoir/gint). It uses the CMake build system added in [fxSDK 2.3](/Lephenixnoir/fxsdk). + +Here's how the files are used: + +* `src` and `include` are your library's code and headers. Unless you have a single header, you'll want to keep the compiler's include folder clean and have all your headers included as ``, so `include` has a single subfolder `example`. +* There is a template header at `include/example/config.h.in` that gets transformed by CMake during build to insert the version number without hardcoding it. You can use it for other compile-time options. +* `CMakeLists.txt` is a pretty standard CMake script that builds the library. +* `cmake/FindLibExample.cmake` is a script for add-ins using your library, so that they can `find_package(LibExample 1.0)` and get all the compile and link options for free. +* `giteapc.make` makes it possible to build and install your library in a simple command using [GiteaPC](/Lephenixnoir/GiteaPC). If you don't want that you can delete it (along with the related `.gitignore` entries). + +## The build system + +Not a lot to discuss here, this is pretty standard. See the [tutorial on Planète Casio](https://www.planet-casio.com/Fr/forums/topic16647-1-tutoriel-compiler-des-add-ins-avec-cmake-fxsdk.html) (in French) for an introduction to CMake in the context of add-ins. You might be interested in [`configure_file()`](https://cmake.org/cmake/help/latest/command/configure_file.html) and [`install()`](https://cmake.org/cmake/help/latest/command/install.html), which are rarely used in add-ins. + +The fxSDK provides three variables to help you install your files: + +* `FXSDK_LIB` is the install path for library files (`*.a`). +* `FXSDK_INCLUDE` is the install path for headers (`*.h`); we use a subfolder `example/` to keep things organized. +* `FXSDK_CMAKE_MODULE_PATH` is the path of an fxSDK folder storing built-in and user-provided CMake modules. These are made visible to anyone that configures with `fxsdk build-{fx,cg}`. + +## The FindPackage file + +`cmake/FindLibExample.cmake` is a module used to search for libexample. The user would request to `find_package(LibExample)` and CMake will look for various options, one of which is a `Find.cmake` file in one of the search directories. + +The goal of a find module is to determine whether the library is available, its version, and there are a couple of options. Most of these are handled by `find_package_handle_standard_args()`, including checking that the user-requested version and the installed version are compatible. + +If the library is found, the find module defines an external target (called "imported") that provides the path to the library and suitable compile and link options. The user can run `target_link_libraries(addin LibExample::LibExample)` and all the flags will be supplied automatically. Whenever you update your library, the library file or the find module will change and all user applications will automatically relink. + +The detection step is here automated with the fxSDK's [`FindSimpleLibrary.cmake`](/Lephenixnoir/fxsdk/src/branch/master/fxsdk/cmake/FindSimpleLibrary.cmake) module. + +## GiteaPC support + +[GiteaPC](/Lephenixnoir/GiteaPC) is a tool to automate building and installing repositories from the Planète Casio Gitea forge. It was designed to speed up library management in the fxSDK. A repository that has the `giteapc` topic (topics can be added through the "Manage topics" link on the repository's front page) and provides `giteapc.make` can be built, installed, and updated with a simple command. + +``` +% giteapc install Lephenixnoir/Template-gint-library +``` + +The job of `giteapc.make` is simply to provide configure, build, install and uninstall commands. CMake [does not support uninstall targets](https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#can-i-do-make-uninstall-with-cmake), but we can simply remove the files that CMake has recorded installing. This might leave empty directories, but it's a good start. + +`giteapc.make` can also specify basic dependencies in the top comment. + +The `giteapc-config.make` file is for the user to customize the build by adding environment variables (such as setting `LIBEXAMPLE_CMAKEOPTS_FX` to change compiler behaviour, or anything they might need). You can provide configurations of your own in `giteapc-config-.cmake` (they can be installed with `giteapc install Lephenixnoir/Template-gint-library:name`). See [sh-elf-gcc](/Lephenixnoir/sh-elf-gcc) for an example of custom configurations. + +## License + +All the files in this repository are [licensed under CC0](https://creativecommons.org/publicdomain/zero/1.0/); you can use them in any way you want under no conditions whatsoever (this is compatible with the GPL : [[1]](https://wiki.creativecommons.org/wiki/CC0_FAQ#May_I_apply_CC0_to_computer_software.3F_If_so.2C_is_there_a_recommended_implementation.3F), [[2]](https://www.gnu.org/licenses/license-list.html#PublicDomain)). diff --git a/cmake/FindLibExample.cmake b/cmake/FindLibExample.cmake new file mode 100644 index 0000000..09d452c --- /dev/null +++ b/cmake/FindLibExample.cmake @@ -0,0 +1,47 @@ +find_package(Gint 2.1 REQUIRED) + +# Ask the fxSDK to find a library called libexample.a, and find its version in +# the macro EX_VERSION of the header file . +# +# Store the path to libexample.a in EX_PATH and store the version number in +# EX_VERSION. +include(FindSimpleLibrary) +find_simple_library(libexample.a example/config.h "EX_VERSION" + PATH_VAR EX_PATH + VERSION_VAR EX_VERSION) + +# The fxSDK looks for libexample.a in ${FXSDK_LIB}, then in +# ${FXSDK_INCLUDE}, and extracts the version number from a macro like +# +# #define EX_VERSION "..." +# +# See the source code for the FindSimpleLibrary module for more detail. + +# We then use a CMake function to finish searching the library. We specify: +# * REQUIRED_VARS ... which requires the variables to be non-empty, otherwise +# find_library() says the library was not found. +# * VERSION_VAR ... which provides the version number, so that find_library() +# can compare with the version requested by the user (if any) and fail if +# the version we found isn't compatible. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LibExample + REQUIRED_VARS EX_PATH EX_VERSION + VERSION_VAR EX_VERSION) + +# We now have a LibExample_FOUND variable indicating if everything went well. +# If so we can now create an *imported target* that is not built in the project +# but can still be linked against with target_link_libraries(). +if(LibExample_FOUND) + # This is an imported target, we don't build it, we just claim it's here. + add_library(LibExample::LibExample UNKNOWN IMPORTED) + # Here we declare the compiler and linker flags that every user of LibExample + # needs to use. + set_target_properties(LibExample::LibExample PROPERTIES + # If we specify where the library comes from, CMake will watch that file + # and relink any user application when the library is updated! + IMPORTED_LOCATION "${EX_PATH}" + # Linking options + INTERFACE_LINK_OPTIONS -lexample + # Dependencies (for order on the command-line) + INTERFACE_LINK_LIBRARIES Gint::Gint) +endif() diff --git a/giteapc.make b/giteapc.make new file mode 100644 index 0000000..dccb68b --- /dev/null +++ b/giteapc.make @@ -0,0 +1,25 @@ +# giteapc: version=1 depends=Lephenixnoir/gint + +-include giteapc-config.make + +configure: + @ fxsdk build-fx -c $(LIBEXAMPLE_CMAKEOPTS_FX) + @ fxsdk build-cg -c $(LIBEXAMPLE_CMAKEOPTS_CG) + +build: + @ fxsdk build-fx + @ fxsdk build-cg + +install: + @ fxsdk build-fx install + @ fxsdk build-cg install + +uninstall: + @ if [ -e build-fx/install_manifest.txt ]; then \ + xargs rm -f < build-fx/install_manifest.txt; \ + fi + @ if [ -e build-cg/install_manifest.txt ]; then \ + xargs rm -f < build-cg/install_manifest.txt; \ + fi + +.PHONY: configure build install uninstall diff --git a/include/example/add.h b/include/example/add.h new file mode 100644 index 0000000..8edd80f --- /dev/null +++ b/include/example/add.h @@ -0,0 +1,16 @@ +/* libexample: add utilities */ + +#ifndef _EXAMPLE_ADD +#define _EXAMPLE_ADD + +#ifdef __cplusplus +extern "C" { +#endif + +int ex_add(int x, int y); + +#ifdef __cplusplus +} +#endif + +#endif /* _EXAMPLE_ADD */ diff --git a/include/example/config.h.in b/include/example/config.h.in new file mode 100644 index 0000000..4a9ab02 --- /dev/null +++ b/include/example/config.h.in @@ -0,0 +1,9 @@ +/* libexample: compile-time configuration */ + +#ifndef _EXAMPLE_CONFIG +#define _EXAMPLE_CONFIG + +/* The @VAR@ notation is substituted by CMake */ +#define EX_VERSION "@libexample_VERSION@" + +#endif /* _EXAMPLE_CONFIG */ diff --git a/include/example/version.h b/include/example/version.h new file mode 100644 index 0000000..03b1efd --- /dev/null +++ b/include/example/version.h @@ -0,0 +1,23 @@ +/* libexample: version information */ + +#ifndef _EXAMPLE_VERSION +#define _EXAMPLE_VERSION + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Version of the example library */ +char const *ex_version(void); + +/* Version of gint used in this library */ +char const *ex_gint_version(void); +uint32_t ex_gint_hash(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _EXAMPLE_VERSION */ diff --git a/src/add.c b/src/add.c new file mode 100644 index 0000000..aa5cdd6 --- /dev/null +++ b/src/add.c @@ -0,0 +1,6 @@ +#include + +int ex_add(int x, int y) +{ + return x + y; +} diff --git a/src/version.c b/src/version.c new file mode 100644 index 0000000..74f7736 --- /dev/null +++ b/src/version.c @@ -0,0 +1,18 @@ +#include +#include +#include + +char const *ex_version(void) +{ + return EX_VERSION; +} + +char const *ex_gint_version(void) +{ + return GINT_VERSION; +} + +uint32_t ex_gint_hash(void) +{ + return GINT_HASH; +}