Package: src/packages/rtl.fdoc
Run Time Library¶
key | file |
---|---|
flx_rtl.py | $PWD/buildsystem/flx_rtl.py |
flx_compiler_support_bodies.hpp | share/lib/rtl/flx_compiler_support_bodies.hpp |
flx_compiler_support_headers.hpp | share/lib/rtl/flx_compiler_support_headers.hpp |
flx_executil.cpp | share/src/rtl/flx_executil.cpp |
flx_executil.hpp | share/lib/rtl/flx_executil.hpp |
flx_executil.fpc | $PWD/src/config/flx_executil.fpc |
flx_main.cpp | share/src/rtl/flx_main.cpp |
flx_rtl.cpp | share/src/rtl/flx_rtl.cpp |
flx_rtl.hpp | share/lib/rtl/flx_rtl.hpp |
flx_rtl_shapes.cpp | share/src/rtl/flx_rtl_shapes.cpp |
flx_rtl_shapes.hpp | share/lib/rtl/flx_rtl_shapes.hpp |
plat_linux.cpp | share/src/rtl/plat_linux.cpp |
plat_linux.hpp | share/lib/rtl/plat_linux.hpp |
flx_rtl_config.hpp | share/lib/rtl/flx_rtl_config.hpp |
flx_rtl_config.h | share/lib/rtl/flx_rtl_config.h |
flx_rtl_core.fpc | $PWD/src/config/flx_rtl_core.fpc |
flx_thread_free_rtl_core.fpc | $PWD/src/config/flx_thread_free_rtl_core.fpc |
sysdlist.flx | share/lib/std/control/sysdlist.flx |
unix_flx.fpc | $PWD/src/config/unix/flx.fpc |
win_flx.fpc | $PWD/src/config/win/flx.fpc |
Bootstrap builder.¶
#[flx_rtl.py]
import fbuild
from fbuild.functools import call
from fbuild.path import Path
from fbuild.record import Record
from fbuild.builders.file import copy
import buildsystem
from buildsystem.config import config_call
# ------------------------------------------------------------------------------
def build_runtime(phase):
path = Path(phase.ctx.buildroot/'share'/'src', 'rtl')
print("[fbuild] [rtl] MAKING RTL ******* ")
srcs = [f for f in Path.glob(path / '*.cpp')]
includes = [
phase.ctx.buildroot / 'host/lib/rtl',
phase.ctx.buildroot / 'share/lib/rtl'
]
macros = ['BUILD_RTL']
libs = [
call('buildsystem.flx_uint256_t.build_runtime', phase),
#call('buildsystem.flx_integer.build_runtime', phase),
call('buildsystem.flx_strutil.build_runtime', phase),
call('buildsystem.flx_dynlink.build_runtime', phase),
call('buildsystem.flx_async.build_runtime', phase),
call('buildsystem.flx_exceptions.build_runtime', phase),
call('buildsystem.flx_gc.build_runtime', phase),
]
dlfcn_h = config_call('fbuild.config.c.posix.dlfcn_h',
phase.platform,
phase.cxx.static,
phase.cxx.shared)
if dlfcn_h.dlopen:
external_libs = dlfcn_h.external_libs
else:
external_libs = []
dst = 'host/lib/rtl/flx'
return Record(
static=buildsystem.build_cxx_static_lib(phase, dst, srcs,
includes=includes,
macros=macros,
libs=[lib.static for lib in libs],
external_libs=external_libs),
shared=buildsystem.build_cxx_shared_lib(phase, dst, srcs,
includes=includes,
macros=macros,
libs=[lib.shared for lib in libs],
external_libs=external_libs))
Compiler Support¶
//[flx_compiler_support_headers.hpp]
#ifndef __FLX_COMPILER_SUPPORT_HEADERS_H__
#define __FLX_COMPILER_SUPPORT_HEADERS_H__
#include "flx_rtl_config.hpp"
#if defined(FLX_PTF_STATIC_STRUCT) || defined(FLX_PTF_STATIC_PTR)
#error "FLX_PTF_STATIC_STRUCT and FLX_PTF_STATIC_PTR no longer supported"
#endif
#define PTF ptf->
#define FLX_POINTER_TO_THREAD_FRAME ptf
// for declarations in header file
#define FLX_FMEM_DECL thread_frame_t *ptf;
#define FLX_FPAR_DECL_ONLY thread_frame_t *_ptf
#define FLX_FPAR_DECL thread_frame_t *_ptf,
#define FLX_APAR_DECL_ONLY thread_frame_t *ptf
#define FLX_APAR_DECL thread_frame_t *ptf,
#define FLX_DCL_THREAD_FRAME
#if FLX_CGOTO
#define FLX_LOCAL_LABEL_VARIABLE_TYPE void*
#define FLX_PC_DECL void *pc;
#define FLX_KILLPC pc = &&_flx_dead_frame;
#else
#define FLX_PC_DECL int pc;
#define FLX_LOCAL_LABEL_VARIABLE_TYPE int
#define FLX_KILLPC pc = -1;
#endif
#define t typename
#define t2 t,t
#define t3 t,t,t
#define t4 t,t,t,t
#define p template <
#define s > struct
template <typename, int> struct _fix; // fixpoint
template <t,t> struct _ft; // function
template <t,t> struct _cft; // cfunction
template <t,int> struct _at; // array
template <t> struct _pt; // procedure
p t2 s _tt2; // tuples
p t3 s _tt3;
p t4 s _tt4;
p t,t4 s _tt5;
p t2,t4 s _tt6;
p t3,t4 s _tt7;
#undef t
#undef t2
#undef t3
#undef t4
#undef p
#undef s
#endif
//[flx_compiler_support_bodies.hpp]
#ifndef __FLX_COMPILER_SUPPORT_BODIES_H__
#define __FLX_COMPILER_SUPPORT_BODIES_H__
#include "flx_compiler_support_headers.hpp"
#include <algorithm>
//
// convert an rvalue to an lvalue
template<typename T>
T const &lvalue(T const &x)
{
return x;
}
// this reinterpret cast works with rvalues too
template<typename T, typename U>
T &reinterpret(U const &x) {
return reinterpret_cast<T&>(const_cast<U&>(x));
}
// dflt init
template<typename T>
void dflt_init(T *p){ new(p) T(); }
// destroy object
template<typename T>
void destroy(T *p){ p->T::~T(); }
// copy initialise
template<typename T>
void copy_init (T *dst, T *src)
{
new(dst) T(*src);
}
// move initialise
template<typename T>
void move_init (T *dst, T *src)
{
new(dst) T(::std::move(*src));
}
// move initialise, destroy src
template<typename T>
void dmove_init (T *dst, T *src)
{
new(dst) T(::std::move(*src));
destroy (src);
}
// copy assign
template<typename T>
void copy_assign (T *dst, T *src)
{
*dst = *src;
}
// move assign
template<typename T>
void move_assign (T *dst, T *src)
{
*dst = ::std::move(*src);
}
// move assign, destroy src
template<typename T>
void dmove_assign (T *dst, T *src)
{
*dst = ::std::move(*src);
destroy (src);
}
class ValueType
{
virtual size_t object_size_impl()=0;
virtual size_t object_alignment_impl()=0;
virtual void dflt_init_impl (void *)=0;
virtual void destroy_impl (void *)=0;
virtual void copy_init_impl(void *, void *)=0;
virtual void move_init_impl(void *, void *)=0;
virtual void copy_assign_impl(void *, void *)=0;
virtual void move_assign_impl(void *, void *)=0;
public:
size_t object_size() { return object_size_impl(); }
size_t object_alignment() { return object_size_impl(); }
void dflt_init(void *dst) { dflt_init_impl(dst); }
void destroy(void *dst) { destroy_impl (dst); }
void copy_init (void *dst, void *src) { copy_init_impl(dst,src); }
void move_init (void *dst, void *src) { move_init_impl(dst,src); }
void copy_assign(void *dst, void *src) { copy_assign_impl(dst,src); }
void move_assign(void *dst, void *src) { move_assign_impl(dst,src); }
};
template<typename T>
class CxxValueType : public virtual ValueType
{
size_t object_size_impl() { return sizeof(T); }
size_t object_alignment_impl() { return alignof(T); }
void dflt_init_impl(void *dst) { ::dflt_init<T>((T*)dst); }
void destroy_impl(void *dst) { ::dflt_init<T>((T*)dst); }
void copy_init_impl(void *dst, void *src) { ::copy_init<T>((T*)dst,(T*)src); }
void move_init_impl(void *dst, void *src) { ::move_init<T>((T*)dst,(T*)src); }
void copy_assign_impl(void *dst, void *src) { ::copy_assign<T>((T*)dst,(T*)src); }
void move_assign_impl(void *dst, void *src) { ::move_assign<T>((T*)dst,(T*)src); }
};
// object does NOT own the product description array
// should use a shared pointer thing I guess
class ProductType : public virtual ValueType
{
size_t n;
ValueType **cp;
public:
ProductType (ValueType **p, size_t m) : cp(p), n(n) {}
~ProductType();
size_t object_size_impl() override;
size_t object_alignment_impl() override;
void dflt_init_impl (void *) override;
void destroy_impl (void *) override;
void copy_init_impl(void *, void *) override;
void move_init_impl(void *, void *) override;
void copy_assign_impl(void *, void *) override;
void move_assign_impl(void *, void *) override;
};
template<typename T0, typename T1>
struct _tt2 {
T0 mem_0;
T1 mem_1;
_tt2() {}
_tt2 (T0 _a0, T1 _a1) : mem_0(_a0), mem_1(_a1) {}
};
template<typename T0, typename T1, typename T2>
struct _tt3 {
T0 mem_0;
T1 mem_1;
T2 mem_2;
_tt3() {}
_tt3 (T0 _a0, T1 _a1, T2 _a2) :
mem_0(_a0), mem_1(_a1),mem_2(_a2)
{}
};
template<typename T0, typename T1, typename T2, typename T3>
struct _tt4 {
T0 mem_0;
T1 mem_1;
T2 mem_2;
T3 mem_3;
_tt4() {}
_tt4 (T0 _a0, T1 _a1, T2 _a2, T3 _a3) :
mem_0(_a0), mem_1(_a1),mem_2(_a2), mem_3(_a3)
{}
};
template<typename T0, typename T1, typename T2, typename T3, typename T4>
struct _tt5 {
T0 mem_0;
T1 mem_1;
T2 mem_2;
T3 mem_3;
T4 mem_4;
_tt5() {}
_tt5 (T0 _a0, T1 _a1, T2 _a2, T3 _a3, T4 _a4) :
mem_0(_a0), mem_1(_a1),mem_2(_a2), mem_3(_a3), mem_4(_a4)
{}
};
#define FLX_EXEC_FAILURE(f,op,what) \
throw ::flx::rtl::flx_exec_failure_t (f,op,what)
#define FLX_HALT(f,sl,sc,el,ec,s) \
throw ::flx::rtl::flx_halt_t (::flx::rtl::flx_range_srcref_t(f,sl,sc,el,ec),__FILE__,__LINE__,s)
// note call should be trace(&v,...) however that requires
// compiler support to make a trace record for each tracepoint
// so we use NULL for now
#ifdef FLX_ENABLE_TRACE
#define FLX_TRACE(v,f,sl,sc,el,ec,s) \
::flx::rtl::flx_trace (NULL,::flx::rtl::flx_range_srcref_t(f,sl,sc,el,ec),__FILE__,__LINE__,s)
#else
#define FLX_TRACE(v,f,sl,sc,el,ec,s)
#endif
#define FLX_MATCH_FAILURE(f,sl,sc,el,ec) \
throw ::flx::rtl::flx_match_failure_t (::flx::rtl::flx_range_srcref_t(f,sl,sc,el,ec),__FILE__,__LINE__)
#define FLX_DROPTHRU_FAILURE(f,sl,sc,el,ec) \
throw ::flx::rtl::flx_dropthru_failure_t (::flx::rtl::flx_range_srcref_t(f,sl,sc,el,ec),__FILE__,__LINE__)
#define FLX_ASSERT_FAILURE(f,sl,sc,el,ec) \
throw ::flx::rtl::flx_assert_failure_t (::flx::rtl::flx_range_srcref_t(f,sl,sc,el,ec),__FILE__,__LINE__)
#define FLX_ASSERT2_FAILURE(f,sl,sc,el,ec,f2,sl2,sc2,el2,ec2) \
throw ::flx::rtl::flx_assert2_failure_t (\
::flx::rtl::flx_range_srcref_t(f,sl,sc,el,ec),\
::flx::rtl::flx_range_srcref_t(f2,sl2,sc2,el2,sc2),\
__FILE__,__LINE__)
#define FLX_AXIOM_CHECK_FAILURE(f,sl,sc,el,ec,f2,sl2,sc2,el2,ec2) \
throw ::flx::rtl::flx_axiom_check_failure_t (\
::flx::rtl::flx_range_srcref_t(f,sl,sc,el,ec),\
::flx::rtl::flx_range_srcref_t(f2,sl2,sc2,el2,sc2),\
__FILE__,__LINE__)
#define FLX_RANGE_FAILURE(mi,v,ma,f,sl,sc,el,ec) \
throw ::flx::rtl::flx_range_failure_t (mi,v,ma,::flx::rtl::flx_range_srcref_t(f,sl,sc,el,ec),__FILE__,__LINE__)
// for generated code in body file
#define INIT_PC pc=0;
///< interior program counter
#if FLX_CGOTO
#ifdef __clang__
#define FLX_START_SWITCH (&&_start_switch); _start_switch: if(pc)goto *pc;
#else
#define FLX_START_SWITCH _start_switch: if(pc)goto *pc;
#endif
#define FLX_LOCAL_LABEL_ADDRESS(x) &&case_##x
#define FLX_SET_PC(x) pc=&&case_##x;
#define FLX_CASE_LABEL(x) case_##x:;
#define FLX_DECLARE_LABEL(n,i,x) \
extern void f##i##_##n##_##x(void) __asm__("l"#i"_"#n"_"#x);
#define FLX_LABEL(n,i,x) x:\
__asm__(".global l"#i"_"#n"_"#x);\
__asm__("l"#i"_"#n"_"#x":");\
__asm__(""::"g"(&&x));
#define FLX_FARTARGET(n,i,x) (void*)&f##i##_##n##_##x
#define FLX_END_SWITCH \
_flx_dead_frame: throw ::flx::rtl::flx_dead_frame_failure_t(__FILE__,__LINE__);
#else
#define FLX_START_SWITCH _start_switch: switch(pc){case 0:;
#define FLX_LOCAL_LABEL_ADDRESS(x) x
#define FLX_SET_PC(x) pc=x;
#define FLX_CASE_LABEL(x) case x:;
#define FLX_DECLARE_LABEL(n,i,x)
#define FLX_LABEL(n,i,x) case n: x:;
#define FLX_FARTARGET(n,i,x) n
#define FLX_END_SWITCH \
case -1: throw ::flx::rtl::flx_dead_frame_failure_t(__FILE__,__LINE__);\
default: throw ::flx::rtl::flx_switch_failure_t(__FILE__,__LINE__); }
#endif
//
// We do a direct long jump to a target as follows:
//
// If the target frame is just ourself (this)
// we set the pc and just goto the start of the procedure,
// allowing the switch/computed goto there to do the local jump.
//
// If the target is foreign, we force the foreign frame pc
// to the target pc, and then return that frame to the driver
// so it will resume that procedure, executing the starting switch,
// which now jumps to the required location.
//
#define FLX_DIRECT_LONG_JUMP(ja) \
{ \
::flx::rtl::jump_address_t j = ja; \
if(j.target_frame == this) { \
pc = j.local_pc; \
goto _start_switch; \
} else { \
j.target_frame->pc = j.local_pc; \
return j.target_frame; \
} \
}
#define FLX_RETURN \
{ \
con_t *tmp = _caller; \
_caller = 0; \
return tmp; \
}
#define FLX_NEWP(x) new(*PTF gcp,x##_ptr_map,true)x
#define FLX_FINALISER(x) \
static void x##_finaliser(::flx::gc::generic::collector_t *, void *__p){\
((x*)__p)->~x();\
}
#define FLX_FMEM_INIT_ONLY : ptf(_ptf)
#define FLX_FMEM_INIT : ptf(_ptf),
#define FLX_FPAR_PASS_ONLY ptf
#define FLX_FPAR_PASS ptf,
#define FLX_APAR_PASS_ONLY _ptf
#define FLX_APAR_PASS _ptf,
#define _PTF _ptf->
#define _PTFV _ptf
#define FLX_PASS_PTF 1
#define FLX_EAT_PTF(x) x
#define FLX_DEF_THREAD_FRAME
#define FLX_FRAME_WRAPPERS(mname,name) \
extern "C" FLX_EXPORT mname::thread_frame_t *name##_create_thread_frame(\
::flx::gc::generic::gc_profile_t *gcp,\
::flx::run::flx_world *world\
) {\
mname::thread_frame_t *p = new(*gcp,mname::thread_frame_t_ptr_map,false) mname::thread_frame_t();\
p->world = world;\
p->gcp = gcp;\
return p;\
}
// init is a heap procedure
#define FLX_START_WRAPPER(mname,name,x)\
extern "C" FLX_EXPORT ::flx::rtl::con_t *name##_flx_start(\
mname::thread_frame_t *__ptf,\
int argc,\
char **argv,\
FILE *stdin_,\
FILE *stdout_,\
FILE *stderr_\
) {\
__ptf->argc = argc;\
__ptf->argv = argv;\
__ptf->flx_stdin = stdin_;\
__ptf->flx_stdout = stdout_;\
__ptf->flx_stderr = stderr_;\
return (new(*__ptf->gcp,mname::x##_ptr_map,false) \
mname::x(__ptf)) ->call(0);\
}
// init is a stack procedure
#define FLX_STACK_START_WRAPPER_PTF(mname,name,x)\
extern "C" FLX_EXPORT ::flx::rtl::con_t *name##_flx_start(\
mname::thread_frame_t *__ptf,\
int argc,\
char **argv,\
FILE *stdin_,\
FILE *stdout_,\
FILE *stderr_\
) {\
__ptf->argc = argc;\
__ptf->argv = argv;\
__ptf->flx_stdin = stdin_;\
__ptf->flx_stdout = stdout_;\
__ptf->flx_stderr = stderr_;\
mname::x(__ptf).stack_call();\
return 0;\
}
// init is a stack procedure, no PTF
#define FLX_STACK_START_WRAPPER_NOPTF(mname,name,x)\
extern "C" FLX_EXPORT ::flx::rtl::con_t *name##_flx_start(\
mname::thread_frame_t *__ptf,\
int argc,\
char **argv,\
FILE *stdin_,\
FILE *stdout_,\
FILE *stderr_\
) {\
__ptf->argc = argc;\
__ptf->argv = argv;\
__ptf->flx_stdin = stdin_;\
__ptf->flx_stdout = stdout_;\
__ptf->flx_stderr = stderr_;\
mname::x().stack_call();\
return 0;\
}
// init is a C procedure, passed PTF
#define FLX_C_START_WRAPPER_PTF(mname,name,x)\
extern "C" FLX_EXPORT ::flx::rtl::con_t *name##_flx_start(\
mname::thread_frame_t *__ptf,\
int argc,\
char **argv,\
FILE *stdin_,\
FILE *stdout_,\
FILE *stderr_\
) {\
__ptf->argc = argc;\
__ptf->argv = argv;\
__ptf->flx_stdin = stdin_;\
__ptf->flx_stdout = stdout_;\
__ptf->flx_stderr = stderr_;\
mname::x(__ptf);\
return 0;\
}
// init is a C procedure, NOT passed PTF
#define FLX_C_START_WRAPPER_NOPTF(mname,name,x)\
extern "C" FLX_EXPORT ::flx::rtl::con_t *name##_flx_start(\
mname::thread_frame_t *__ptf,\
int argc,\
char **argv,\
FILE *stdin_,\
FILE *stdout_,\
FILE *stderr_\
) {\
mname::x();\
return 0;\
}
#endif
RTL¶
//[flx_rtl.hpp]
#ifndef __FLX_RTL_H__
#define __FLX_RTL_H__
#include "flx_rtl_config.hpp"
#include "flx_exceptions.hpp"
#include "flx_gc.hpp"
#include "flx_serialisers.hpp"
#include "flx_rtl_shapes.hpp"
#include "flx_compiler_support_headers.hpp"
#include "flx_compiler_support_bodies.hpp"
#include "flx_continuation.hpp"
#include "flx_svc.hpp"
#include <string>
#include <functional>
#include <cstdint>
#include <mutex>
#include <list>
#include <atomic>
#include "flx_spinlock.hpp"
namespace flx { namespace rtl {
typedef void *void_pointer;
// ********************************************************
// Compact Linear Type and projection
// ********************************************************
typedef ::std::uint64_t cl_t;
// ********************************************************
// Felix system classes
// ********************************************************
struct RTL_EXTERN muxguard;
// MOVED TO flx_exceptions
//struct RTL_EXTERN con_t; // continuation
struct RTL_EXTERN jump_address_t; // label variable type
struct RTL_EXTERN fthread_t; // f-thread
struct RTL_EXTERN _uctor_; // union constructor
//struct RTL_EXTERN _variant_; // variant constructor
struct RTL_EXTERN schannel_t; // synchronous channel type
struct RTL_EXTERN clptr_t; // pointer to compact linear product component
struct RTL_EXTERN clprj_t; // compact linear projection
struct RTL_EXTERN muxguard {
private:
muxguard() = delete;
muxguard(muxguard const&) = delete;
muxguard *operator=(muxguard const&)=delete;
::std::mutex *m;
public:
muxguard (::std::mutex *p);
~muxguard ();
};
// MOVE THIS TO RTL AND PROVIDE SUITABLE RTTI SO GC KNOWS ABOUT THE FRAME POINTER
struct RTL_EXTERN jump_address_t
{
con_t *target_frame;
FLX_LOCAL_LABEL_VARIABLE_TYPE local_pc;
jump_address_t (con_t *tf, FLX_LOCAL_LABEL_VARIABLE_TYPE lpc) :
target_frame (tf), local_pc (lpc)
{}
jump_address_t () : target_frame (0), local_pc(0) {}
jump_address_t (con_t *tf) : target_frame(tf), local_pc(0) {}
// default copy constructor and assignment
};
// ********************************************************
/// FTHREAD. Felix threads
// ********************************************************
struct RTL_EXTERN fthread_t // fthread abstraction
{
con_t *cc; ///< current continuation
fthread_t *next; ///< link to next fthread, to be used in scheduler queue and schannels
fthread_t(); ///< dead thread, suitable for assignment
fthread_t(con_t*); ///< make thread from a continuation
svc_req_t *run(); ///< run until dead or driver service request
void kill(); ///< kill by detaching the continuation
svc_req_t *get_svc()const; ///< get current service request of waiting thread
private: // uncopyable
fthread_t(fthread_t const&) = delete;
void operator=(fthread_t const&) = delete;
};
// ********************************************************
/// SCHANNEL. Synchronous channels
// ********************************************************
struct RTL_EXTERN schannel_t
{
fthread_t *top; // has to be public for offsetof macro
void push_reader(fthread_t *); ///< add a reader
fthread_t *pop_reader(); ///< pop a reader, NULL if none
void push_writer(fthread_t *); ///< add a writer
fthread_t *pop_writer(); ///< pop a writer, NULL if none
schannel_t();
private: // uncopyable
schannel_t(schannel_t const&) = delete;
void operator= (schannel_t const&) = delete;
};
// ********************************************************
/// VARIANTS. Felix union type
/// note: non-polymorphic, so ctor can be inline
// ********************************************************
struct RTL_EXTERN _uctor_
{
int variant; ///< Variant code
void *data; ///< Heap variant constructor data
_uctor_() : variant(-1), data(0) {}
_uctor_(int i, void *d) : variant(i), data(d) {}
_uctor_(int *a, _uctor_ x) : variant(a[x.variant]), data(x.data) {}
};
// ********************************************************
/// VARIANTS. Felix variant type
/// note: non-polymorphic, so ctor can be inline
// ********************************************************
/* NOT USED ANY MORE
struct RTL_EXTERN _variant_
{
char const *vname; ///< Variant code
void *vdata; ///< Heap variant constructor data
_variant_() : vname(""), vdata(0) {}
_variant_(char const *n, void *d) : vname(n), vdata(d) {}
};
*/
// ********************************************************
/// COMPACT LINEAR PROJECTIONS
// ********************************************************
struct RTL_EXTERN clprj_t
{
cl_t divisor;
cl_t modulus;
clprj_t () : divisor(1), modulus(-1) {}
clprj_t (cl_t d, cl_t m) : divisor (d), modulus (m) {}
};
// reverse compose projections left \odot right
inline clprj_t rcompose (clprj_t left, clprj_t right) {
return clprj_t (left.divisor * right.divisor, right.modulus);
}
// apply projection to value
inline cl_t apply (clprj_t prj, cl_t v) {
return v / prj.divisor % prj.modulus;
}
// ********************************************************
/// COMPACT LINEAR POINTERS
// ********************************************************
struct RTL_EXTERN clptr_t
{
cl_t *p;
cl_t divisor;
cl_t modulus;
clptr_t () : p(0), divisor(1),modulus(-1) {}
clptr_t (cl_t *_p, cl_t d, cl_t m) : p(_p), divisor(d),modulus(m) {}
// upgrade from ordinary pointer
clptr_t (cl_t *_p, cl_t siz) : p (_p), divisor(1), modulus(siz) {}
};
// apply projection to pointer
inline clptr_t applyprj (clptr_t cp, clprj_t d) {
return clptr_t (cp.p, d.divisor * cp.divisor, d.modulus);
}
// dereference
inline cl_t clt_deref(clptr_t q) { return *q.p / q.divisor % q.modulus; }
// storeat
inline void storeat (clptr_t q, cl_t v) {
*q.p = *q.p - (*q.p / q.divisor % q.modulus) * q.divisor + v * q.divisor;
//*q.p -= ((*q.p / q.divisor % q.modulus) - v) * q.divisor; //???
}
struct flx_trace_t
{
size_t count;
int enable_trace;
};
extern RTL_EXTERN int flx_enable_trace;
RTL_EXTERN void flx_trace(flx_trace_t* tr,flx_range_srcref_t sr, char const *file, int line, char const *msg);
}} // namespaces
#endif
//[flx_rtl.cpp]
#include "flx_rtl.hpp"
#include "flx_rtl_shapes.hpp"
#include <cstdio>
#include <cassert>
#include <cstddef>
#include <stdint.h>
#include "flx_exceptions.hpp"
#include "flx_collector.hpp"
#include "flx_serialisers.hpp"
#include "flx_continuation.hpp"
// main run time library code
namespace flx { namespace rtl {
muxguard::muxguard (::std::mutex *p): m(p) { if (m)m->lock(); }
muxguard::~muxguard () { if (m)m->unlock(); }
// ********************************************************
// fthread_t implementation
// ********************************************************
fthread_t::fthread_t() : cc(nullptr), next(nullptr) {}
fthread_t::fthread_t(con_t *a) : cc(a), next(nullptr) {}
void fthread_t::kill() { cc = nullptr; }
svc_req_t *fthread_t::get_svc()const { return cc?cc->p_svc:nullptr; }
svc_req_t *fthread_t::run() {
if(!cc) return nullptr; // dead
restep:
cc->p_svc = nullptr;
step:
//fprintf(stderr,"[fthread_t::run::step] cc=%p->",cc);
try { cc = cc->resume(); }
catch (con_t *x) { cc = x; }
//fprintf(stderr,"[fthread_t::run::step] ->%p\n",cc);
if(!cc) return nullptr; // died
if(cc->p_svc)
{
//fprintf(stderr,"[fthread_t::run::service call] ->%d\n",cc->p_svc);
switch(cc->p_svc->svc_req)
{
/*
case svc_get_fthread:
// NEW VARIANT LAYOUT RULES
// One less level of indirection here
//**(fthread_t***)(cc->p_svc->data) = this;
*(fthread_t**)(cc->p_svc->data) = this;
goto restep; // handled
*/
//case svc_yield:
// goto restep;
// we don't know what to do with the request,
// so pass the buck to the driver
default:
return cc->p_svc;
}
}
goto step;
}
// ********************************************************
// schannel_t implementation
// ********************************************************
schannel_t::schannel_t () : top(nullptr) {}
// PRECONDITION: channel is empty or has readers
void schannel_t::push_reader(fthread_t *r)
{
r->next = top;
top = r;
}
// PRECONDITION: channel is empty or has writers
void schannel_t::push_writer(fthread_t *w)
{
w->next = top;
top = (fthread_t*)((uintptr_t)w | 1u);
}
fthread_t *schannel_t::pop_reader()
{
if (top == nullptr || (uintptr_t)top & 1u) return nullptr; // NULL or low bit set
fthread_t *tmp = top;
top = tmp->next;
tmp->next = nullptr; // for GC
return tmp;
}
fthread_t *schannel_t::pop_writer()
{
if (!((uintptr_t)top & 1u)) return nullptr; // low bit clear (includes NULL case)
fthread_t *tmp = (fthread_t*)((uintptr_t)top & ~(uintptr_t)1u); // mask out low bit
top = tmp->next;
tmp->next = nullptr; // for GC
return tmp;
}
// ********************************************************
// trace feature
// ********************************************************
int flx_enable_trace=1;
size_t flx_global_trace_count=0uL;
void flx_trace(flx_trace_t* tr,flx_range_srcref_t sr, char const *file, int line, char const *msg)
{
if(!flx_enable_trace)return;
flx_global_trace_count++;
if(tr)
{
tr->count++;
if(tr->enable_trace)
{
fprintf(stderr,"%zu : %s\n",tr->count,msg);
print_loc(stderr,sr,file,line);
}
}
else
{
fprintf(stderr,"%zu : %s\n",flx_global_trace_count,msg);
print_loc(stderr,sr,file,line);
}
}
}}
ProductType::~ProductType(){}
size_t ProductType::object_size_impl() {
size_t s = 0;
for (int i=0; i<n; ++i) s+=cp[i]->object_size();
return s;
}
size_t ProductType::object_alignment_impl() {
size_t s = 0;
for (int i=0; i<n; ++i) s = ::std::max(s,cp[i]->object_alignment());
return s;
}
// if a is aligned then a%amt == 0
// otherwise a%amt is the amount over the previously aligned
// address, so we subtract it to get the previously aligned address
// and then add the amt back to get the next one.
uintptr_t round_up (uintptr_t a, size_t amt) {
size_t adj = a % amt;
return adj? a + amt - a%amt:a;
}
#define INCR(p,a) *(unsigned char **)p += a;
void *round_up (void *a, size_t amt) {
return (void*)round_up((uintptr_t)a, amt);
}
void ProductType::dflt_init_impl (void *p) {
for (int i = 0; i<n; ++i) {
auto vt = cp[i];
p = round_up(p,vt->object_alignment());
vt->dflt_init(p);
INCR(p,vt->object_size());
}
};
void ProductType::destroy_impl (void *p) {
for (int i = 0; i<n; ++i) {
auto vt = cp[i];
p = round_up(p,vt->object_alignment());
vt->destroy(p);
INCR(p,vt->object_size());
}
}
void ProductType::copy_init_impl(void *dst, void *src) {
for (int i = 0; i<n; ++i) {
auto vt = cp[i];
auto align = vt->object_alignment();
src = round_up(src,align);
dst = round_up(dst,align);
vt->copy_init(dst,src);
auto z = vt->object_size();
INCR(src,z);
INCR(dst,z);
}
}
void ProductType::move_init_impl(void *dst, void *src) {
for (int i = 0; i<n; ++i) {
auto vt = cp[i];
auto align = vt->object_alignment();
src = round_up(src,align);
dst = round_up(dst,align);
vt->move_init(dst,src);
auto z = vt->object_size();
INCR(src, z);
INCR(dst, z);
}
}
void ProductType::copy_assign_impl(void *dst, void *src) {
for (int i = 0; i<n; ++i) {
auto vt = cp[i];
auto align = vt->object_alignment();
src = round_up(src,align);
dst = round_up(dst,align);
vt->copy_assign(dst,src);
auto z = vt->object_size();
INCR(src, z);
INCR(dst, z);
}
}
void ProductType::move_assign_impl(void *dst, void *src) {
for (int i = 0; i<n; ++i) {
auto vt = cp[i];
auto align = vt->object_alignment();
src = round_up(src,align);
dst = round_up(dst,align);
vt->move_assign(dst,src);
auto z = vt->object_size();
INCR(src, z);
INCR(dst, z);
}
}
Exec Util¶
//[flx_executil.hpp]
#ifndef FLX_EXECUTIL
#define FLX_EXECUTIL
#include "flx_rtl_config.hpp"
#include "flx_rtl.hpp"
#include "flx_sync.hpp"
#include "flx_gc.hpp"
namespace flx { namespace rtl { namespace executil {
RTL_EXTERN void run(flx::rtl::con_t *c);
RTL_EXTERN void frun (::flx::gc::generic::gc_profile_t* gcp, ::flx::rtl::con_t *p);
}}}
#endif
//[flx_executil.cpp]
#include "flx_executil.hpp"
namespace flx { namespace rtl { namespace executil {
void run(::flx::rtl::con_t *p)
{
while(p)
{
try { p=p->resume(); }
catch (::flx::rtl::con_t *x) { p = x; }
}
}
void frun (::flx::gc::generic::gc_profile_t* gcp, ::flx::rtl::con_t *p)
{
::flx::run::fthread_list *q = new(*gcp,::flx::run::fthread_list_ptr_map,false) ::flx::run::fthread_list(gcp);
::flx::run::sync_sched *ss =
new(*gcp,::flx::run::sync_sched_ptr_map,false) ::flx::run::sync_sched(false, gcp, q)
;
::flx::rtl::fthread_t *ft =
new(*gcp,::flx::rtl::_fthread_ptr_map,false) ::flx::rtl::fthread_t(p)
;
gcp->collector->add_root(ss);
ss->frun();
gcp->collector->remove_root(ss);
}
}}}
//[flx_executil.fpc]
Name: flx_executil
Description: Felix mini scheduler
Requires: flx
includes: '"flx_executil.hpp"'
Main¶
//[flx_main.cpp]
#include "flx_rtl_config.hpp"
#include "flx_rtl.hpp"
// THIS IS A DO NOTHING MAINLINE FOR USE WHEN STATICALLY LINKING
#include "stdio.h"
extern "C" RTL_EXTERN ::flx::rtl::con_t *flx_main( void *p){
//fprintf(stderr, "DUMMY flx_main()\n");
return 0;
}
Shapes¶
//[flx_rtl_shapes.hpp]
#ifndef __FLX_RTL_SHAPES_HPP__
#define __FLX_RTL_SHAPES_HPP__
#include "flx_rtl_config.hpp"
#include "flx_gc.hpp"
namespace flx { namespace rtl {
// ********************************************************
// Shape (RTTI) objects for system classes
// con_t is only an abstract base, so has no fixed shape
// shapes for instance types generated by Felix compiler
// we provide a shape for C 'int' type as well
// ********************************************************
// special: just the offset data for a pointer
RTL_EXTERN extern ::flx::gc::generic::offset_data_t const _address_offset_data;
RTL_EXTERN extern ::flx::gc::generic::gc_shape_t _fthread_ptr_map;
RTL_EXTERN extern ::flx::gc::generic::gc_shape_t schannel_ptr_map;
RTL_EXTERN extern ::flx::gc::generic::gc_shape_t _uctor_ptr_map;
//RTL_EXTERN extern ::flx::gc::generic::gc_shape_t _variant_ptr_map;
RTL_EXTERN extern ::flx::gc::generic::gc_shape_t _int_ptr_map;
RTL_EXTERN extern ::flx::gc::generic::gc_shape_t _address_ptr_map;
//RTL_EXTERN extern ::flx::gc::generic::gc_shape_t _caddress_ptr_map;
RTL_EXTERN extern ::flx::gc::generic::gc_shape_t clptr_t_ptr_map;
RTL_EXTERN extern ::flx::gc::generic::gc_shape_t clprj_t_ptr_map;
RTL_EXTERN extern ::flx::gc::generic::gc_shape_t jump_address_ptr_map;
RTL_EXTERN extern ::flx::gc::generic::gc_shape_t cl_t_ptr_map;
}}
#endif
//[flx_rtl_shapes.cpp]
#include "flx_rtl_shapes.hpp"
#include "flx_rtl.hpp"
#include "flx_dynlink.hpp"
#include <stddef.h>
namespace flx { namespace rtl {
// ********************************************************
//OFFSETS for fthread_t
// ********************************************************
static const std::size_t _fthread_offsets[2]={
offsetof(fthread_t,cc),
offsetof(fthread_t,next)
};
static ::flx::gc::generic::offset_data_t const _fthread_offset_data = { 2, _fthread_offsets };
::flx::gc::generic::gc_shape_t _fthread_ptr_map = {
"rtl::fthread_t",
1,sizeof(fthread_t),
0,
0, // fcops
&_fthread_offset_data,
::flx::gc::generic::scan_by_offsets,
::flx::gc::generic::tblit<fthread_t>,::flx::gc::generic::tunblit<fthread_t>,
gc::generic::gc_flags_immobile,
0UL, 0UL
};
// ********************************************************
//OFFSETS for schannel_t
// ********************************************************
static const std::size_t schannel_offsets[1]={
offsetof(schannel_t,top),
};
static ::flx::gc::generic::offset_data_t const schannel_offset_data = { 1, schannel_offsets };
::flx::gc::generic::gc_shape_t schannel_ptr_map = {
"rtl::schannel_t",
1,sizeof(schannel_t),
0, // no finaliser
0, // fcops
&schannel_offset_data, // scanner data
::flx::gc::generic::scan_by_offsets, // scanner
::flx::gc::generic::tblit<schannel_t>, // encoder
::flx::gc::generic::tunblit<schannel_t>, // decoder
gc::generic::gc_flags_default,
0UL, 0UL
};
// ********************************************************
// _uctor_ implementation
// ********************************************************
//OFFSETS for _uctor_
static const std::size_t _uctor_offsets[1]= {
offsetof(_uctor_,data)
};
static ::flx::gc::generic::offset_data_t const _uctor_offset_data = { 1, _uctor_offsets };
static CxxValueType<_uctor_> _uctor_fcops {};
::flx::gc::generic::gc_shape_t _uctor_ptr_map = {
"rtl::_uctor_",
1,
sizeof(_uctor_),
0, // finaliser
&_uctor_fcops, // fcops
&_uctor_offset_data, // scanner data
::flx::gc::generic::scan_by_offsets, // scanner
::flx::gc::generic::tblit<_uctor_>, // encoder
::flx::gc::generic::tunblit<_uctor_>, // decoder
gc::generic::gc_flags_default
};
/*
// ********************************************************
// _variant_ implementation
// ********************************************************
//OFFSETS for _variant_
static const std::size_t _variant_offsets[1]= {
offsetof(_variant_,vdata)
};
static CxxValueType<_variant_> _variant_fcops {};
static ::flx::gc::generic::offset_data_t const _variant_offset_data = { 1, _variant_offsets };
::flx::gc::generic::gc_shape_t _variant_ptr_map = {
"rtl::_variant_",
1,
sizeof(_variant_),
0, // finaliser
&_variant_fcops, // fcops
&_variant_offset_data, // scanner data
::flx::gc::generic::scan_by_offsets, // scanner
::flx::gc::generic::tblit<_variant_>, // encoder
::flx::gc::generic::tunblit<_variant_>, // decoder
gc::generic::gc_flags_default
};
*/
static CxxValueType<int> int_fcops {};
// ********************************************************
// jump_address implementation
// ********************************************************
//OFFSETS for jump_address
static const std::size_t jump_address_offsets[1]= {
offsetof(jump_address_t,target_frame)
};
static ::flx::gc::generic::offset_data_t const
jump_address_offset_data = { 1, jump_address_offsets }
;
static CxxValueType<jump_address_t> jump_address_t_fcops {};
::flx::gc::generic::gc_shape_t jump_address_ptr_map = {
"rtl::jump_address_t",
1,
sizeof(_uctor_),
0, // finaliser
&jump_address_t_fcops, // fcops
&jump_address_offset_data, // scanner data
::flx::gc::generic::scan_by_offsets, // scanner
::flx::gc::generic::tblit<jump_address_t>, // encoder
::flx::gc::generic::tunblit<jump_address_t>, // decoder
gc::generic::gc_flags_default
};
// ********************************************************
// int implementation
// ********************************************************
::flx::gc::generic::gc_shape_t _int_ptr_map = {
"rtl::int",
1,
sizeof(int),
0, // finaliser
&int_fcops,
//0, // fcops
0, // scanner data
0, // scanner
::flx::gc::generic::tblit<int>, // encoder
::flx::gc::generic::tunblit<int>, // decoder
gc::generic::gc_flags_default,
0UL, 0UL
};
// ********************************************************
// cl_t implementation
// ********************************************************
static CxxValueType<cl_t> cl_t_fcops {};
::flx::gc::generic::gc_shape_t cl_t_ptr_map = {
"rtl::cl_t",
1,
sizeof(cl_t),
0, // finaliser
&cl_t_fcops, // fcops
0, // scanner data
0, // scanner
::flx::gc::generic::tblit<cl_t>,
::flx::gc::generic::tunblit<cl_t>,
gc::generic::gc_flags_default,
0UL, 0UL
};
// ********************************************************
// clptr_t implementation
// ********************************************************
static CxxValueType<clptr_t> clptr_t_fcops {};
static const std::size_t _clptr_t_offsets[1]={ 0 };
::flx::gc::generic::offset_data_t const _clptr_t_offset_data = { 1, _clptr_t_offsets };
::flx::gc::generic::gc_shape_t clptr_t_ptr_map = {
"rtl::clptr_t",
1,
sizeof(clptr_t),
0, // finaliser
&clptr_t_fcops, // fcops
&_clptr_t_offset_data, // scanner data
::flx::gc::generic::scan_by_offsets, // scanner
::flx::gc::generic::tblit<clptr_t>,
::flx::gc::generic::tunblit<clptr_t>,
gc::generic::gc_flags_default,
0UL, 0UL
};
// ********************************************************
// clprj_t implementation
// ********************************************************
static CxxValueType<clprj_t> clprj_t_fcops {};
::flx::gc::generic::offset_data_t const _clprj_t_offset_data = { 0, NULL };
::flx::gc::generic::gc_shape_t clprj_t_ptr_map = {
"rtl::clprj_t",
1,
sizeof(clprj_t),
0, // finaliser
&clprj_t_fcops, // fcops
0, // scanner data
::flx::gc::generic::scan_by_offsets, // scanner
::flx::gc::generic::tblit<clprj_t>,
::flx::gc::generic::tunblit<clprj_t>,
gc::generic::gc_flags_default,
0UL, 0UL
};
// ********************************************************
// pointer implementation
// ********************************************************
//OFFSETS for address
static const std::size_t _address_offsets[1]={ 0 };
::flx::gc::generic::offset_data_t const _address_offset_data = { 1, _address_offsets };
static ::std::string address_encoder (void *p) {
return ::flx::gc::generic::blit (p,sizeof (void*));
}
static size_t address_decoder (void *p, char *s, size_t i) {
return ::flx::gc::generic::unblit (p,sizeof (void*),s,i);
}
// ********************************************************
// address implementation : MUST BE LAST because the compiler
// uses "address_ptr_map" as the back link for generated shape tables
// ********************************************************
::flx::gc::generic::gc_shape_t _address_ptr_map = {
"rtl::address",
1,
sizeof(void*),
0, // finaliser
0, // fcops
&_address_offset_data, /// scanner data
::flx::gc::generic::scan_by_offsets, // scanner
::flx::gc::generic::tblit<void*>, // encoder
::flx::gc::generic::tunblit<void*>, // decoder
gc::generic::gc_flags_default,
0UL, 0UL
};
}}
Plat Linux¶
//[plat_linux.hpp]
#ifndef __PLAT_LINUX_H__
#define __PLAT_LINUX_H__
int get_cpu_nr();
#endif
//[plat_linux.cpp]
#define STAT "/proc/stat"
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "plat_linux.hpp"
// return number of cpus
int get_cpu_nr()
{
FILE *fp;
char line[16];
int proc_nb, cpu_nr = -1;
if ((fp = fopen(STAT, "r")) == NULL) {
fprintf(stderr, ("Cannot open %s: %s\n"), STAT, strerror(errno));
exit(1);
}
while (fgets(line, 16, fp) != NULL) {
if (strncmp(line, "cpu ", 4) && !strncmp(line, "cpu", 3)) {
char* endptr = NULL;
proc_nb = strtol(line + 3, &endptr, 0);
if (!(endptr && *endptr == '\0')) {
fprintf(stderr, "unable to parse '%s' as an integer in %s\n", line + 3, STAT);
exit(1);
}
if (proc_nb > cpu_nr)
cpu_nr = proc_nb;
}
}
fclose(fp);
return (cpu_nr + 1);
}
Macro config stuff¶
Here flx_rtl_config.hpp depends on flx_rtl_config.h which depends on flx_rtl_config_params.hpp which is generated by the configuration system.
//[flx_rtl_config.hpp]
#ifndef __FLX_RTL_CONFIG_HPP__
#define __FLX_RTL_CONFIG_HPP__
#include "flx_rtl_config.h"
#include <stdint.h>
// get variant index code and pointer from packed variant rep
#define FLX_VP(x) ((void*)((uintptr_t)(x) & ~(uintptr_t)0x03))
#define FLX_VI(x) ((int)((uintptr_t)(x) & (uintptr_t)0x03))
// make a packed variant rep from index code and pointer
#define FLX_VR(i,p) ((void*)((uintptr_t)(p)|(uintptr_t)(i)))
// get variant index code and pointer from nullptr variant rep
#define FLX_VNP(x) (x)
#define FLX_VNI(x) ((int)(x!=0))
// make a nullptr variant rep from index code and pointer
#define FLX_VNR(i,p) (p)
#endif
//[flx_rtl_config.h]
#ifndef __FLX_RTL_CONFIG_H__
#define __FLX_RTL_CONFIG_H__
#include "flx_rtl_config_params.hpp"
#include <setjmp.h>
#if FLX_HAVE_GNU_BUILTIN_EXPECT
#define FLX_UNLIKELY(x) __builtin_expect(long(x),0)
#define FLX_LIKELY(x) __builtin_expect(long(x),1)
#else
#define FLX_UNLIKELY(x) x
#define FLX_LIKELY(x) x
#endif
#define FLX_SAVE_REGS \
jmp_buf reg_save_on_stack; \
setjmp (reg_save_on_stack)
//
#if FLX_HAVE_CGOTO && FLX_HAVE_ASM_LABELS
#define FLX_CGOTO 1
#else
#define FLX_CGOTO 0
#endif
#if FLX_WIN32 && !defined(_WIN32_WINNT)
#define _WIN32_WINNT 0x0600 // Require Windows NT5 (2K, XP, 2K3)
#endif
#if FLX_WIN32 && !defined(WINVER)
#define WINVER 0x0600 // Require Windows NT5 (2K, XP, 2K3)
#endif
#if FLX_WIN32
// vs windows.h just LOVES to include winsock version 1 headers by default.
// that's bad for everyone, so quit it.
#define _WINSOCKAPI_
// windows.h defines min/max macros, which can cause all sorts of confusion.
#ifndef NOMINMAX
#define NOMINMAX
#endif
#endif
#if FLX_WIN32
#if defined(FLX_STATIC_LINK)
#define FLX_EXPORT
#define FLX_IMPORT
#else
#define FLX_EXPORT __declspec(dllexport)
#define FLX_IMPORT __declspec(dllimport)
#endif
#else
// All modules on Unix are compiled with -fvisibility=hidden
// All API symbols get visibility default
// whether or not we're static linking or dynamic linking (with -fPIC)
#define FLX_EXPORT __attribute__((visibility("default")))
#define FLX_IMPORT __attribute__((visibility("default")))
#endif
#ifdef BUILD_RTL
#define RTL_EXTERN FLX_EXPORT
#else
#define RTL_EXTERN FLX_IMPORT
#endif
#if FLX_MACOSX && !FLX_HAVE_DLOPEN
#define FLX_MACOSX_NODLCOMPAT 1
#else
#define FLX_MACOSX_NODLCOMPAT 0
#endif
#if FLX_HAVE_GNU
#define FLX_ALWAYS_INLINE __attribute__ ((always_inline))
#define FLX_NOINLINE __attribute__ ((noinline))
#define FLX_CONST __attribute__ ((const))
#define FLX_PURE __attribute__ ((pure))
#define FLX_GXX_PARSER_HACK (void)0,
#define FLX_UNUSED __attribute__((unused))
#else
#define FLX_ALWAYS_INLINE
#define FLX_NOINLINE
#define FLX_CONST
#define FLX_PURE
#define FLX_GXX_PARSER_HACK
#define FLX_UNUSED
#endif
#endif
//[flx_rtl_core.fpc]
Description: Felix Core Run Time Libraries
Requires: flx flx_gc
Requires: flx_exceptions flx_pthread flx_async
Requires: re2 flx_dynlink demux faio
Requires: flx_uint256_t
Requires: sqlite3
//[flx_thread_free_rtl_core.fpc]
Description: Felix Core Run Time Libraries (no threads, no async I/O)
Requires: flx flx_gc flx_thread_free_run
Requires: flx_exceptions
Requires: re2 flx_dynlink
Requires: flx_uint256_t
Requires: sqlite3
//[unix_flx.fpc]
Name: flx
Description: Felix core runtime support
provides_dlib: -lflx_dynamic
provides_slib: -lflx_static
Requires: flx_gc flx_exceptions flx_pthread flx_dynlink
library: rtl
includes: '"flx_rtl.hpp"' <iostream> <cstdio> <cstddef> <cassert> <climits> <string>
macros: BUILD_RTL
srcdir: src/rtl
src: .*\.cpp
//[win_flx.fpc]
Name: flx
Description: Felix core runtime support
provides_dlib: /DEFAULTLIB:flx_dynamic
provides_slib: /DEFAULTLIB:flx_static
Requires: flx_gc flx_exceptions flx_pthread flx_dynlink
library: rtl
includes: '"flx_rtl.hpp"' <iostream> <cstdio> <cstddef> <cassert> <climits> <string>
macros: BUILD_RTL
srcdir: src/rtl
src: .*\.cpp