From 1e77e25675d27da641722f384ffe55060fcc9960 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 16 Jun 2016 01:27:21 +0300 Subject: [PATCH] examples/embedding: Example for embedding MicroPython in an app. --- examples/embedding/Makefile | 8 + examples/embedding/Makefile.upylib | 200 ++++++++++++++++++++++ examples/embedding/hello-embed.c | 74 ++++++++ examples/embedding/mpconfigport.h | 1 + examples/embedding/mpconfigport_minimal.h | 138 +++++++++++++++ 5 files changed, 421 insertions(+) create mode 100644 examples/embedding/Makefile create mode 100644 examples/embedding/Makefile.upylib create mode 100644 examples/embedding/hello-embed.c create mode 120000 examples/embedding/mpconfigport.h create mode 100644 examples/embedding/mpconfigport_minimal.h diff --git a/examples/embedding/Makefile b/examples/embedding/Makefile new file mode 100644 index 0000000000..99f239a7c5 --- /dev/null +++ b/examples/embedding/Makefile @@ -0,0 +1,8 @@ +MPTOP = ../.. +CFLAGS = -std=c99 -I. -I$(MPTOP) -DNO_QSTR +LDFLAGS = -L. + +hello-embed: hello-embed.o -lmicropython + +-lmicropython: + $(MAKE) -f $(MPTOP)/examples/embedding/Makefile.upylib MPTOP=$(MPTOP) diff --git a/examples/embedding/Makefile.upylib b/examples/embedding/Makefile.upylib new file mode 100644 index 0000000000..d8dbade3fe --- /dev/null +++ b/examples/embedding/Makefile.upylib @@ -0,0 +1,200 @@ +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)/unix +#INC += -I../lib/timeutils +INC += -I$(BUILD) + +# compiler settings +CWARN = -Wall -Werror +CWARN += -Wpointer-arith -Wuninitialized +CFLAGS = $(INC) $(CWARN) -ansi -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../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 ../lib/libffi/build_dir/out/lib/libffi-*/include) + ifeq ($(MICROPY_FORCE_32BIT),1) + LIBFFI_LDFLAGS_MOD = ../lib/libffi/build_dir/out/lib32/libffi.a + else + LIBFFI_LDFLAGS_MOD = ../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 $(MPTOP)/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 \ + ) + +ifeq ($(MICROPY_FATFS),1) +LIB_SRC_C += $(addprefix lib/,\ + fatfs/ff.c \ + fatfs/option/ccsbcs.c \ + ) +endif + +OBJ = $(PY_O) +OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(STMHAL_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 overriden. +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 ../lib/libffi; git clean -d -x -f + cd ../lib/libffi; ./autogen.sh + mkdir -p ../lib/libffi/build_dir; cd ../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: ../lib/axtls/README + cd ../lib/axtls; cp config/upyconfig config/.config + cd ../lib/axtls; make oldconfig -B + cd ../lib/axtls; make clean + cd ../lib/axtls; make all CC="$(CC)" LD="$(LD)" + +../lib/axtls/README: + @echo "You cloned without --recursive, fetching submodules for you." + (cd ..; git submodule update --init --recursive) diff --git a/examples/embedding/hello-embed.c b/examples/embedding/hello-embed.c new file mode 100644 index 0000000000..1949305184 --- /dev/null +++ b/examples/embedding/hello-embed.c @@ -0,0 +1,74 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * 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 +#include + +#include "py/compile.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "py/stackctrl.h" + +static char heap[16384]; + +mp_obj_t execute_from_lexer(mp_lexer_t *lex) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_parse_tree_t pt = mp_parse(lex, MP_PARSE_FILE_INPUT); + mp_obj_t module_fun = mp_compile(&pt, lex->source_name, MP_EMIT_OPT_NONE, false); + mp_call_function_0(module_fun); + nlr_pop(); + return 0; + } else { + // uncaught exception + return (mp_obj_t)nlr.ret_val; + } +} + +int main() { + // Initialized stack limit + mp_stack_set_limit(40000 * (BYTES_PER_WORD / 4)); + // Initialize heap + gc_init(heap, heap + sizeof(heap)); + // Initialize interpreter + mp_init(); + + const char str[] = "print('Hello world of easy embedding!')"; + mp_lexer_t *lex = mp_lexer_new_from_str_len(0/*MP_QSTR_*/, str, strlen(str), false); + if (execute_from_lexer(lex)) { + printf("Error\n"); + } +} + +uint mp_import_stat(const char *path) { + return MP_IMPORT_STAT_NO_EXIST; +} + +void nlr_jump_fail(void *val) { + printf("FATAL: uncaught NLR %p\n", val); + exit(1); +} diff --git a/examples/embedding/mpconfigport.h b/examples/embedding/mpconfigport.h new file mode 120000 index 0000000000..142e5d6f43 --- /dev/null +++ b/examples/embedding/mpconfigport.h @@ -0,0 +1 @@ +mpconfigport_minimal.h \ No newline at end of file diff --git a/examples/embedding/mpconfigport_minimal.h b/examples/embedding/mpconfigport_minimal.h new file mode 100644 index 0000000000..9f080ab0e1 --- /dev/null +++ b/examples/embedding/mpconfigport_minimal.h @@ -0,0 +1,138 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * 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 Micro Python is built + +#define MICROPY_ALLOC_PATH_MAX (PATH_MAX) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_ENABLE_FINALISER (0) +#define MICROPY_STACK_CHECK (0) +#define MICROPY_COMP_CONST (0) +#define MICROPY_MEM_STATS (0) +#define MICROPY_DEBUG_PRINTERS (0) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_HELPER_LEXER_UNIX (1) +#define MICROPY_ENABLE_SOURCE_LINE (0) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) +#define MICROPY_WARNINGS (0) +#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE) +#define MICROPY_STREAMS_NON_BLOCK (0) +#define MICROPY_OPT_COMPUTED_GOTO (0) +#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0) +#define MICROPY_CAN_OVERRIDE_BUILTINS (0) +#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0) +#define MICROPY_CPYTHON_COMPAT (0) +#define MICROPY_PY_BUILTINS_BYTEARRAY (0) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (0) +#define MICROPY_PY_BUILTINS_COMPILE (0) +#define MICROPY_PY_BUILTINS_ENUMERATE (0) +#define MICROPY_PY_BUILTINS_FILTER (0) +#define MICROPY_PY_BUILTINS_FROZENSET (0) +#define MICROPY_PY_BUILTINS_REVERSED (0) +#define MICROPY_PY_BUILTINS_SET (0) +#define MICROPY_PY_BUILTINS_SLICE (0) +#define MICROPY_PY_BUILTINS_STR_UNICODE (0) +#define MICROPY_PY_BUILTINS_PROPERTY (0) +#define MICROPY_PY_BUILTINS_MIN_MAX (0) +#define MICROPY_PY___FILE__ (0) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (0) +#define MICROPY_PY_GC (0) +#define MICROPY_PY_GC_COLLECT_RETVAL (0) +#define MICROPY_PY_ARRAY (0) +#define MICROPY_PY_COLLECTIONS (0) +#define MICROPY_PY_MATH (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_IO (0) +#define MICROPY_PY_IO_FILEIO (0) +#define MICROPY_PY_STRUCT (0) +#define MICROPY_PY_SYS (1) +#define MICROPY_PY_SYS_EXIT (0) +#define MICROPY_PY_SYS_PLATFORM "linux" +#define MICROPY_PY_SYS_MAXSIZE (0) +#define MICROPY_PY_SYS_STDFILES (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_UCTYPES (0) +#define MICROPY_PY_UZLIB (0) +#define MICROPY_PY_UJSON (0) +#define MICROPY_PY_URE (0) +#define MICROPY_PY_UHEAPQ (0) +#define MICROPY_PY_UHASHLIB (0) +#define MICROPY_PY_UBINASCII (0) + +extern const struct _mp_obj_module_t mp_module_os; + +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&mp_module_os }, \ + +#define MICROPY_PORT_ROOT_POINTERS \ + mp_obj_t keyboard_interrupt_obj; + +////////////////////////////////////////// +// Do not change anything beyond this line +////////////////////////////////////////// + +// Define to 1 to use undertested inefficient GC helper implementation +// (if more efficient arch-specific one is not available). +#ifndef MICROPY_GCREGS_SETJMP + #ifdef __mips__ + #define MICROPY_GCREGS_SETJMP (1) + #else + #define MICROPY_GCREGS_SETJMP (0) + #endif +#endif + +// type definitions for the specific machine + +#ifdef __LP64__ +typedef long mp_int_t; // must be pointer size +typedef unsigned long mp_uint_t; // must be pointer size +#else +// These are definitions for machines where sizeof(int) == sizeof(void*), +// regardless for actual size. +typedef int mp_int_t; // must be pointer size +typedef unsigned int mp_uint_t; // must be pointer size +#endif + +#define BYTES_PER_WORD sizeof(mp_int_t) + +// Cannot include , as it may lead to symbol name clashes +#if _FILE_OFFSET_BITS == 64 && !defined(__LP64__) +typedef long long mp_off_t; +#else +typedef long mp_off_t; +#endif + +typedef void *machine_ptr_t; // must be of pointer size +typedef const void *machine_const_ptr_t; // must be of pointer size + +// We need to provide a declaration/definition of alloca() +#ifdef __FreeBSD__ +#include +#else +#include +#endif