diff --git a/.travis.yml b/.travis.yml index f6fe3e1e4e39f..e919a498e87a8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -362,3 +362,12 @@ jobs: script: - make ${MAKEOPTS} -C ports/powerpc UART=potato - make ${MAKEOPTS} -C ports/powerpc UART=lpc_serial + + # libmicropython via examples/embedding + - stage: test + env: NAME="examples/embedding build" + install: + - gcc --version + - python3 --version + script: + - make ${MAKEOPTS} -C examples/embedding diff --git a/examples/embedding/.gitignore b/examples/embedding/.gitignore new file mode 100644 index 0000000000000..e36b360c03afe --- /dev/null +++ b/examples/embedding/.gitignore @@ -0,0 +1 @@ +hello-embed diff --git a/examples/embedding/Makefile b/examples/embedding/Makefile index 99f239a7c5af8..6b531373da901 100644 --- a/examples/embedding/Makefile +++ b/examples/embedding/Makefile @@ -1,8 +1,47 @@ -MPTOP = ../.. -CFLAGS = -std=c99 -I. -I$(MPTOP) -DNO_QSTR -LDFLAGS = -L. +MICROPY_TOP ?= ../.. -hello-embed: hello-embed.o -lmicropython +# Get the absolute path to the directory (so that all paths passed to +# libmicropython build can be absolute). +ABS_PATH = $(realpath .) --lmicropython: - $(MAKE) -f $(MPTOP)/examples/embedding/Makefile.upylib MPTOP=$(MPTOP) +LIBMICROPYTHON_PORT=$(MICROPY_TOP)/ports/libmicropython +LIBMICROPYTHON_BUILD=$(ABS_PATH)/build-libmicropython +LIBMICROPYTHON_A=$(LIBMICROPYTHON_BUILD)/libmicropython.a + +CFLAGS = -std=c99 + +# For mpconfigport.h libmicropython headers. +INC += -I$(LIBMICROPYTHON_PORT) + +# For generated headers from the libmicropython build. +INC += -I$(LIBMICROPYTHON_BUILD) + +# For all MicroPython headers. +INC += -I$(MICROPY_TOP) + +CFLAGS += $(INC) + +hello-embed: hello-embed.o $(LIBMICROPYTHON_A) + +hello-embed.o: $(LIBMICROPYTHON_A) + +V ?= 0 + +# Overrides: +# BUILD to set the directory for compile artifacts. +# LIBMICROPYTHON to set the output path for libmicropython.a +# MICROPY_QSTRDEFSEMBED_H to use our custom qstrdefsembed.h +# MICROPY_MPCONFIGEMBED_H to use our custom mpconfigembed.h +# V to inherit our verbosity setting +$(LIBMICROPYTHON_A): qstrdefsembed.h mpconfigembed.h + @$(MAKE) \ + -C $(LIBMICROPYTHON_PORT) \ + BUILD=$(LIBMICROPYTHON_BUILD) \ + LIBMICROPYTHON=$(LIBMICROPYTHON_A) \ + MICROPY_QSTRDEFSEMBED_H=$(ABS_PATH)/qstrdefsembed.h \ + MICROPY_MPCONFIGEMBED_H=$(ABS_PATH)/mpconfigembed.h \ + V=$(V) \ + lib + +clean: + rm -rf *.o hello-embed $(LIBMICROPYTHON_BUILD) diff --git a/examples/embedding/Makefile.upylib b/examples/embedding/Makefile.upylib deleted file mode 100644 index 0e388332e68fa..0000000000000 --- a/examples/embedding/Makefile.upylib +++ /dev/null @@ -1,191 +0,0 @@ -MPTOP = ../.. --include mpconfigport.mk -include $(MPTOP)/py/mkenv.mk - -all: lib - -# OS name, for simple autoconfig -UNAME_S := $(shell uname -s) - -# include py core make definitions -include $(MPTOP)/py/py.mk - -INC += -I. -INC += -I.. -INC += -I$(MPTOP) -INC += -I$(MPTOP)/ports/unix -INC += -I$(BUILD) - -# compiler settings -CWARN = -Wall -Werror -CWARN += -Wpointer-arith -Wuninitialized -CFLAGS = $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA) - -# Debugging/Optimization -ifdef DEBUG -CFLAGS += -g -COPT = -O0 -else -COPT = -Os #-DNDEBUG -# _FORTIFY_SOURCE is a feature in gcc/glibc which is intended to provide extra -# security for detecting buffer overflows. Some distros (Ubuntu at the very least) -# have it enabled by default. -# -# gcc already optimizes some printf calls to call puts and/or putchar. When -# _FORTIFY_SOURCE is enabled and compiling with -O1 or greater, then some -# printf calls will also be optimized to call __printf_chk (in glibc). Any -# printfs which get redirected to __printf_chk are then no longer synchronized -# with printfs that go through mp_printf. -# -# In MicroPython, we don't want to use the runtime library's printf but rather -# go through mp_printf, so that stdout is properly tied into streams, etc. -# This means that we either need to turn off _FORTIFY_SOURCE or provide our -# own implementation of __printf_chk. We've chosen to turn off _FORTIFY_SOURCE. -# It should also be noted that the use of printf in MicroPython is typically -# quite limited anyways (primarily for debug and some error reporting, etc -# in the unix version). -# -# Information about _FORTIFY_SOURCE seems to be rather scarce. The best I could -# find was this: https://securityblog.redhat.com/2014/03/26/fortify-and-you/ -# Original patchset was introduced by -# https://gcc.gnu.org/ml/gcc-patches/2004-09/msg02055.html . -# -# Turning off _FORTIFY_SOURCE is only required when compiling with -O1 or greater -CFLAGS += -U _FORTIFY_SOURCE -endif - -# On OSX, 'gcc' is a symlink to clang unless a real gcc is installed. -# The unix port of MicroPython on OSX must be compiled with clang, -# while cross-compile ports require gcc, so we test here for OSX and -# if necessary override the value of 'CC' set in py/mkenv.mk -ifeq ($(UNAME_S),Darwin) -CC = clang -# Use clang syntax for map file -LDFLAGS_ARCH = -Wl,-map,$@.map -else -# Use gcc syntax for map file -LDFLAGS_ARCH = -Wl,-Map=$@.map,--cref -endif -LDFLAGS = $(LDFLAGS_MOD) $(LDFLAGS_ARCH) -lm $(LDFLAGS_EXTRA) - -ifeq ($(MICROPY_FORCE_32BIT),1) -# Note: you may need to install i386 versions of dependency packages, -# starting with linux-libc-dev:i386 -ifeq ($(MICROPY_PY_FFI),1) -ifeq ($(UNAME_S),Linux) -CFLAGS_MOD += -I/usr/include/i686-linux-gnu -endif -endif -endif - -ifeq ($(MICROPY_USE_READLINE),1) -INC += -I$(MPTOP)/lib/mp-readline -CFLAGS_MOD += -DMICROPY_USE_READLINE=1 -LIB_SRC_C_EXTRA += mp-readline/readline.c -endif -ifeq ($(MICROPY_USE_READLINE),2) -CFLAGS_MOD += -DMICROPY_USE_READLINE=2 -LDFLAGS_MOD += -lreadline -# the following is needed for BSD -#LDFLAGS_MOD += -ltermcap -endif -ifeq ($(MICROPY_PY_TIME),1) -CFLAGS_MOD += -DMICROPY_PY_TIME=1 -SRC_MOD += modtime.c -endif -ifeq ($(MICROPY_PY_TERMIOS),1) -CFLAGS_MOD += -DMICROPY_PY_TERMIOS=1 -SRC_MOD += modtermios.c -endif -ifeq ($(MICROPY_PY_SOCKET),1) -CFLAGS_MOD += -DMICROPY_PY_SOCKET=1 -SRC_MOD += modsocket.c -endif - -ifeq ($(MICROPY_PY_FFI),1) - -ifeq ($(MICROPY_STANDALONE),1) -LIBFFI_CFLAGS_MOD := -I$(shell ls -1d $(MPTOP)/lib/libffi/build_dir/out/lib/libffi-*/include) - ifeq ($(MICROPY_FORCE_32BIT),1) - LIBFFI_LDFLAGS_MOD = $(MPTOP)/lib/libffi/build_dir/out/lib32/libffi.a - else - LIBFFI_LDFLAGS_MOD = $(MPTOP)/lib/libffi/build_dir/out/lib/libffi.a - endif -else -LIBFFI_CFLAGS_MOD := $(shell pkg-config --cflags libffi) -LIBFFI_LDFLAGS_MOD := $(shell pkg-config --libs libffi) -endif - -ifeq ($(UNAME_S),Linux) -LIBFFI_LDFLAGS_MOD += -ldl -endif - -CFLAGS_MOD += $(LIBFFI_CFLAGS_MOD) -DMICROPY_PY_FFI=1 -LDFLAGS_MOD += $(LIBFFI_LDFLAGS_MOD) -SRC_MOD += modffi.c -endif - -MAIN_C = main.c - -# source files -SRC_C = $(addprefix ports/unix/,\ - $(MAIN_C) \ - gccollect.c \ - unix_mphal.c \ - input.c \ - file.c \ - modmachine.c \ - modos.c \ - moduselect.c \ - alloc.c \ - coverage.c \ - fatfs_port.c \ - $(SRC_MOD) \ - ) - -LIB_SRC_C = $(addprefix lib/,\ - $(LIB_SRC_C_EXTRA) \ - utils/printf.c \ - timeutils/timeutils.c \ - ) - -OBJ = $(PY_O) -OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) - -# List of sources for qstr extraction -SRC_QSTR += $(SRC_C) $(LIB_SRC_C) -# Append any auto-generated sources that are needed by sources listed in -# SRC_QSTR -SRC_QSTR_AUTO_DEPS += - -include $(MPTOP)/py/mkrules.mk - -# Value of configure's --host= option (required for cross-compilation). -# Deduce it from CROSS_COMPILE by default, but can be overridden. -ifneq ($(CROSS_COMPILE),) -CROSS_COMPILE_HOST = --host=$(patsubst %-,%,$(CROSS_COMPILE)) -else -CROSS_COMPILE_HOST = -endif - -deplibs: libffi axtls - -# install-exec-recursive & install-data-am targets are used to avoid building -# docs and depending on makeinfo -libffi: - cd $(MPTOP)/lib/libffi; git clean -d -x -f - cd $(MPTOP)/lib/libffi; ./autogen.sh - mkdir -p $(MPTOP)/lib/libffi/build_dir; cd $(MPTOP)/lib/libffi/build_dir; \ - ../configure $(CROSS_COMPILE_HOST) --prefix=$$PWD/out CC="$(CC)" CXX="$(CXX)" LD="$(LD)"; \ - make install-exec-recursive; make -C include install-data-am - -axtls: $(MPTOP)/lib/axtls/README - cd $(MPTOP)/lib/axtls; cp config/upyconfig config/.config - cd $(MPTOP)/lib/axtls; make oldconfig -B - cd $(MPTOP)/lib/axtls; make clean - cd $(MPTOP)/lib/axtls; make all CC="$(CC)" LD="$(LD)" - -$(MPTOP)/lib/axtls/README: - @echo "You cloned without --recursive, fetching submodules for you." - (cd $(MPTOP); git submodule update --init --recursive) diff --git a/examples/embedding/README.md b/examples/embedding/README.md index 0dfc52e1dcad3..259999f47e48b 100644 --- a/examples/embedding/README.md +++ b/examples/embedding/README.md @@ -1,67 +1,123 @@ -Example of embedding MicroPython in a standalone C application -============================================================== +Embedding MicroPython in a standalone C application +=================================================== -This directory contains a (very simple!) example of how to embed a MicroPython -in an existing C application. - -A C application is represented by the file `hello-embed.c`. It executes a simple -Python statement which prints to the standard output. +This example demonstrates how MicroPython can be used in an existing codebase. +Unlike a regular port, MicroPython is first packaged into a static library +(`libmicropython.a`), which is then linked into a program (`hello-embed.c`). Building the example -------------------- -Building the example is as simple as running: +To compile `hello-embed`, run make -It's worth to trace what's happening behind the scenes though: +this will first build `libmicropython.a`, then link it into the sample program. + +About the example +----------------- + +This example demonstrates: + +1. How to parse, compile and execute a fragment of Python code. +2. How to access Python objects from C (e.g. via globals). +3. Working with MicroPython exceptions. +4. Overriding inline/compile-time functionality in MicroPython core. +5. Adding additional QSTR definitions. + +TODO: +1. Define custom modules. +2. Implementing builtin functionality like filesystem access. +3. How to hook into existing modules like `machine`. +4. Frozen Python modules. + + +Configuration +------------- + +A default configuration is provided by libmicropython's `mpconfigport.h`, but +this can be overriden using `mpconfigembed.h` (this works in a similar way to +the way `mpconfigboard.h` is used in regular ports). + +This is useful for: + +1. Enabling and disabling features. + +2. Hooks and overrides of inline functionality (i.e. where a hook is +implemented via a preprocessor macro rather than a function). -1. As a first step, a MicroPython library is built. This is handled by a -separate makefile, `Makefile.upylib`. It is more or less complex, but the -good news is that you won't need to change anything in it, just use it -as is, the main `Makefile` shows how. What may require editing though is -a MicroPython configuration file. MicroPython is highly configurable, so -you would need to build a library suiting your application well, while -not bloating its size. Check the options in the file `mpconfigport.h`. -Included is a copy of the "minimal" Unix port, which should be a good start -for minimal embedding. For the list of all available options, see -`py/mpconfig.h`. +libmicropython provides generic implementations of -2. Once the MicroPython library is built, your application is compiled -and linked it. The main Makefile is very simple and shows that the changes -you would need to do to your application's `Makefile` (or other build -configuration) are also simple: +* `gc_collect` (supports x86/x64/ARM) +* `mp_import_stat` (always returns NO_EXIST) +* `mp_hal_stdout_tx_strn` (writes to STDOUT_FILENO) -a) You would need to use C99 standard (you're using this 15+ years old -standard already, not a 25+ years old one, right?). +but these are weak symbols so they can be overriden by embedders. -b) You need to provide a path to MicroPython's top-level dir, for includes. +QSTRs +----- -c) You need to include `-DNO_QSTR` compile-time flag. +MicroPython uses interned strings which are defined in the codebase using the +`MP_QSTR_...` macro and automatically extracted by the build process. See +`docs/develop/qstr.rst` for more information. -d) Otherwise, just link with the MicroPython library produced in step 1. +Unfortunately this means that `libmicropython.a` already contains the final +set of QSTRs, and any additional ones defined in the host program will not be +found. As a workaround, additional QSTRs can be passed to the libmicropython +build via `qstrdefsembed.h`. In the future this file could be automatically +generated via a similar extraction mechanism. + +Error string compression is not enabled, although MP_ERROR_TEXT should still +be used for error strings. Out of tree build ----------------- -This example is set up to work out of the box, being part of the MicroPython -tree. Your application of course will be outside of its tree, but the -only thing you need to do is to pass `MPTOP` variable pointing to -MicroPython directory to both Makefiles (in this example, the main Makefile -automatically passes it to `Makefile.upylib`; in your own Makefile, don't forget -to use a suitable value). +This example is designed to work standalone, i.e. you can copy this +`embedding` directory and `make` it from anywhere on the filesystem -- it does +not have to be part of the MicroPython repo. The only requirement is to override +`MICROPY_TOP`. e.g. + + make MICROPY_TOP=/path/to/micropython + +Git submodules provide a convenient way to include the MicroPython repo in +your codebase and pin it at a specific version. + +In a real embedding scenario you would need to adapt the rules from this +sample `Makefile` into your project's existing makefile (or other build +system). + + +Other build systems +------------------- + +As long as your build system has a way to shell out to `make` to build the +libmicropython `lib` target, it should be possible to adapt this +example to any build system. + +You can pass the following variables to the `lib` target in the +ports/libmicropython makefile: + +1. `BUILD`: set the directory for compile artifacts. +2. `LIBMICROPYTHON`: set the output path for libmicropython.a. +3. `MICROPY_QSTRDEFSEMBED_H`: additional QSTR definitions (see qstrdefsembed.h for an example). +4. `MICROPY_MPCONFIGEMBED_H`: additional compile-time configuration (see mpconfigembed.h for an example). + +Any paths must be absolute. + + +Other architectures +------------------- -A practical way to embed MicroPython in your application is to include it -as a git submodule. Suppose you included it as `libs/micropython`. Then in -your main Makefile you would have something like: +The libmicropython build additionally supports cross compilation, and you can +use the `CROSS_COMPILE` and `CFLAGS_EXTRA` variables to customise this in the +libmicropython build. -~~~ -MPTOP = libs/micropython +For example, the following could be used to build `libmicropython.a` for ARM +Cortex M0: -my_app: $(MY_OBJS) -lmicropython + CROSS_COMPILE=arm-none-eabi- CFLAGS_EXTRA="-mthumb -mtune=cortex-m0 -mcpu=cortex-m0" --lmicropython: - $(MAKE) -f $(MPTOP)/examples/embedding/Makefile.upylib MPTOP=$(MPTOP) -~~~ +You will likely want to inherit these from your existing project configuration. diff --git a/examples/embedding/hello-embed.c b/examples/embedding/hello-embed.c index 2000b703c11c6..5d30ed71dc8aa 100644 --- a/examples/embedding/hello-embed.c +++ b/examples/embedding/hello-embed.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2016 Paul Sokolovsky + * Copyright (c) 2020 Jim Mussared * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -32,13 +33,16 @@ #include "py/runtime.h" #include "py/gc.h" #include "py/stackctrl.h" +#include "py/qstr.h" +// Use a fixed static buffer for the heap. static char heap[16384]; mp_obj_t execute_from_str(const char *str) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { - qstr src_name = 1/*MP_QSTR_*/; + // Use the empty string as the "filename". + qstr src_name = MP_QSTR_; mp_lexer_t *lex = mp_lexer_new_from_str_len(src_name, str, strlen(str), false); mp_parse_tree_t pt = mp_parse(lex, MP_PARSE_FILE_INPUT); mp_obj_t module_fun = mp_compile(&pt, src_name, false); @@ -51,22 +55,56 @@ mp_obj_t execute_from_str(const char *str) { } } +void shutdown_hook(void) { + printf("Shutdown hook called.\n"); +} + int main() { - // Initialized stack limit + // Configure stack limit and heap (with our static buffer). mp_stack_set_limit(40000 * (BYTES_PER_WORD / 4)); - // Initialize heap gc_init(heap, heap + sizeof(heap)); - // Initialize interpreter + + // Initialise MicroPython. mp_init(); - const char str[] = "print('Hello world of easy embedding!')"; - if (execute_from_str(str)) { + nlr_buf_t nlr; + + // Execute a print statement. + const char str_print[] = "print('Hello, MicroPython World!')"; + if (execute_from_str(str_print)) { printf("Error\n"); } -} -uint mp_import_stat(const char *path) { - return MP_IMPORT_STAT_NO_EXIST; + // Set a global variable. + const char str_set_global[] = "hello_embed_world = 22"; + if (execute_from_str(str_set_global)) { + printf("Error\n"); + } + + // Read back the global variable (see qstrdefsembed.h for where the QSTR is defined). + if (nlr_push(&nlr) == 0) { + mp_obj_dict_t *globals = mp_globals_get(); + mp_obj_t v = mp_obj_dict_get(MP_OBJ_FROM_PTR(globals), MP_ROM_QSTR(MP_QSTR_hello_embed_world)); + printf("hello_embed_world = %d\n", mp_obj_get_int(v)); + nlr_pop(); + } else { + // uncaught exception + printf("Error\n"); + } + + // Simple exception handling. + if (nlr_push(&nlr) == 0) { + printf("Raising a test exception..."); + mp_raise_ValueError(MP_ERROR_TEXT("embed exception")); + nlr_pop(); + } else { + printf(" caught: "); + mp_obj_t exc = (mp_obj_t)nlr.ret_val; + mp_obj_print_exception(&mp_plat_print, exc); + } + + // Deinitialise MicroPython. + mp_deinit(); } void nlr_jump_fail(void *val) { diff --git a/examples/embedding/mpconfigembed.h b/examples/embedding/mpconfigembed.h new file mode 100644 index 0000000000000..bd82cbedcb253 --- /dev/null +++ b/examples/embedding/mpconfigembed.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jim Mussared + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Options to control how MicroPython is built. + +// Demo handler showing how to customise inline functionality that gets linked +// into libmicropython.a. +void shutdown_hook(void); + +#define MICROPY_PORT_DEINIT_FUNC shutdown_hook() diff --git a/examples/embedding/mpconfigport.h b/examples/embedding/mpconfigport.h deleted file mode 100644 index 89c180b2a8153..0000000000000 --- a/examples/embedding/mpconfigport.h +++ /dev/null @@ -1 +0,0 @@ -#include "mpconfigport_minimal.h" diff --git a/examples/embedding/qstrdefsembed.h b/examples/embedding/qstrdefsembed.h new file mode 100644 index 0000000000000..8ba207e90f63c --- /dev/null +++ b/examples/embedding/qstrdefsembed.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jim Mussared + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// qstrs to add to libmicropython required by this example. + +// *FORMAT-OFF* + +Q(hello_embed_world) diff --git a/ports/libmicropython/Makefile b/ports/libmicropython/Makefile new file mode 100644 index 0000000000000..9bf8ebbe590a0 --- /dev/null +++ b/ports/libmicropython/Makefile @@ -0,0 +1,69 @@ +include ../../py/mkenv.mk +-include mpconfigport.mk + +all: lib + +# QSTR definitions (must come before including py.mk). +QSTR_DEFS = $(MICROPY_QSTRDEFSEMBED_H) +QSTR_GLOBAL_DEPENDENCIES = $(MICROPY_MPCONFIGEMBED_H) + +# Include py core make definitions. +include $(TOP)/py/py.mk + +# Force a full QSTR rebuild if mpconfigembed.h changes. +$(HEADER_BUILD)/qstrdefs.generated.h: $(MICROPY_MPCONFIGEMBED_H) + +INC += -I. +INC += -I.. +INC += -I$(TOP) +INC += -I$(BUILD) + +# Compiler settings. +CWARN = -Wall -Werror +CWARN += -Wpointer-arith -Wuninitialized +CFLAGS = $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA) + +# Debugging/Optimization +ifdef DEBUG +COPT = -O0 +else +COPT = -Os -DNDEBUG +# See explanation in ports/unix/Makefile. +CFLAGS += -U _FORTIFY_SOURCE +endif + +CFLAGS += -g + +LDFLAGS_ARCH = -Wl,-map,$@.map + +ifeq ($(CC),clang) +# Use gcc syntax for map file. +LDFLAGS_ARCH += -Wl,-Map=$@.map,--cref +endif + +LDFLAGS = $(LDFLAGS_MOD) $(LDFLAGS_ARCH) -lm $(LDFLAGS_EXTRA) + +SRC_C += \ + libmicropython.c \ + lib/utils/interrupt_char.c \ + lib/utils/gchelper_generic.c \ + lib/utils/stdout_helpers.c \ + +OBJ = $(PY_O) +OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) + +# List of sources for qstr extraction. +SRC_QSTR += $(SRC_C) $(LIB_SRC_C) +# Append any auto-generated sources that are needed by sources listed in. +# SRC_QSTR +SRC_QSTR_AUTO_DEPS += + +include $(TOP)/py/mkrules.mk + +CLEAN_EXTRA += $(LIBMICROPYTHON) + +# Allow embedder to specify an mpconfigembed.h. +ifneq ($(MICROPY_MPCONFIGEMBED_H),) +CFLAGS += -DMICROPY_MPCONFIGEMBED_H='<$(MICROPY_MPCONFIGEMBED_H)>' +endif diff --git a/ports/libmicropython/README.md b/ports/libmicropython/README.md new file mode 100644 index 0000000000000..580e7d2f56b4e --- /dev/null +++ b/ports/libmicropython/README.md @@ -0,0 +1,6 @@ +libmicropython +============== + +This "port" provides a way to compile MicroPython core into a static library. + +Please see `examples/embedding` for more information. diff --git a/ports/libmicropython/libmicropython.c b/ports/libmicropython/libmicropython.c new file mode 100644 index 0000000000000..f1bc68bc39f32 --- /dev/null +++ b/ports/libmicropython/libmicropython.c @@ -0,0 +1,60 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jim Mussared + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/compile.h" +#include "py/gc.h" +#include "py/runtime.h" + +#include "lib/utils/gchelper.h" + +// Stub implementation of port-specific functionality to simplify embedding on +// ARM/x86/x64 platforms with STDOUT. + +// These are weak symbols, so an embedder can override as necessary. + +MP_WEAK void gc_collect(void) { + gc_collect_start(); + + // Use gchelper implementation for this arch. + gc_helper_collect_regs_and_stack(); + + // trace root pointers from any threads + #if MICROPY_PY_THREAD + mp_thread_gc_others(); + #endif + + gc_collect_end(); +} + +MP_WEAK void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { + write(STDOUT_FILENO, str, len); +} + +MP_WEAK mp_import_stat_t mp_import_stat(const char *path) { + return MP_IMPORT_STAT_NO_EXIST; +} diff --git a/examples/embedding/mpconfigport_minimal.h b/ports/libmicropython/mpconfigport.h similarity index 90% rename from examples/embedding/mpconfigport_minimal.h rename to ports/libmicropython/mpconfigport.h index b5ffd376aeb22..0cd5b09c65d51 100644 --- a/examples/embedding/mpconfigport_minimal.h +++ b/ports/libmicropython/mpconfigport.h @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2015 Damien P. George + * Copyright (c) 2020 Jim Mussared * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,7 +25,17 @@ * THE SOFTWARE. */ -// options to control how MicroPython is built +// Options to control how MicroPython is built. + +// Allow mpconfigembed.h to be provided by the embedder. +#ifdef MICROPY_MPCONFIGEMBED_H +#include MICROPY_MPCONFIGEMBED_H +#endif + +// Default options for libmicropython.a (based originally on unix/minimal). + +// TODO: Remove any that already match the mpconfig.h default, and allow +// overriding in mpconfigembed.h by wrapping them with #ifndefs. #define MICROPY_ALLOC_PATH_MAX (PATH_MAX) #define MICROPY_ENABLE_GC (1) @@ -89,19 +100,9 @@ extern const struct _mp_obj_module_t mp_module_os; #define MICROPY_PORT_BUILTIN_MODULES \ - { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_os) }, \ #define MICROPY_PORT_ROOT_POINTERS \ -////////////////////////////////////////// -// Do not change anything beyond this line -////////////////////////////////////////// - -#if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) -// Fall back to setjmp() implementation for discovery of GC pointers in registers. -#define MICROPY_GCREGS_SETJMP (1) -#endif - // type definitions for the specific machine #ifdef __LP64__ diff --git a/ports/libmicropython/mphalport.h b/ports/libmicropython/mphalport.h new file mode 100644 index 0000000000000..5253e94f51d8c --- /dev/null +++ b/ports/libmicropython/mphalport.h @@ -0,0 +1,27 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jim Mussared + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "lib/utils/interrupt_char.h" diff --git a/py/mkrules.mk b/py/mkrules.mk index c37c25db4bd2f..77362bd83ef2f 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -189,7 +189,7 @@ ifneq ($(GIT_SUBMODULES),) endif .PHONY: submodules -LIBMICROPYTHON = libmicropython.a +LIBMICROPYTHON ?= libmicropython.a # We can execute extra commands after library creation using # LIBMICROPYTHON_EXTRA_CMD. This may be needed e.g. to integrate pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy