import ln_scons
Import('env')

AddOption('--test', metavar="TEST_DIR", help="build test-executable from libln/tests/TEST_DIR")
AddOption('--without-parameters', dest='without_parameters', default=False, action='store_true', help="build without parameter support")

if GetOption("help"):
    # early exit here not to execute config checks
    Return()

env.Prepend(CPPPATH=["include"])

sources = Glob("src/*.c") + ["src/sharedlnclient.cpp"]

if not GetOption('without_parameters'):
    env.Append(
        LIBS=[ "string_util" ]
    )
    if not GetOption("help") and not GetOption("clean"):
        conf = env.CloneConfigureEnv().Configure()
        if not conf.CheckCXXHeader("string_util/string_util.h"):
            print("please install libstring_util e.g. from https://gitlab.com/links_and_nodes/libstring_util")
            Exit(1)
        conf.Finish()
    sources.append("src/parameters.cpp")

msg_defs_used = """
ln2/request_topic
ln/parameters/query
ln/parameters/query_dict
ln/parameters/override_dict_single
ln/parameters/request_parameter_topic
ln/event/call
ln/event/connect
ln/log_service
"""
env.ln_generate("include/ln/client_lib_messages.h", msg_defs_used, "../share/message_definitions", sources)
env.write_version_h("include/ln/version.h", "LIBLN_VERSION", sources=sources)

env["GENERATE_LN_ERRORS_H"] = "$PYTHON %s" % File("scripts/generate_ln_errors_h")
errors_h = env.Command("include/ln/errors.h", "include/ln/ln.h", "$GENERATE_LN_ERRORS_H $SOURCE $TARGET")
[ Depends(fn, errors_h) for fn in sources ]

libln_major = 1 # only changes for breaking changes in libln API
libln_minor = env.find_define_value("include/ln/ln.h", "LN_LIBRARY_VERSION")
cenv = env.Clone()

libs = []
if not hasattr(env, "need_to_link_rt") or env.need_to_link_rt:
    libs += ["rt"]

if not GetOption("clean"):
    cenv.Append(
        LIBS=libs,
        CFLAGS=cenv.set_stdflag("gnu99")
    )
    conf = cenv.CloneConfigureEnv().Configure()
    have_futex_atomic_intrinsics = conf.TryCompile("""
        #include <stdint.h>
        #include <sys/syscall.h>
        int main(void) {
        #ifdef SYS_futex
            uint32_t value = 0;
            __atomic_store_n(&value, 1, __ATOMIC_RELAXED);
            return __atomic_load_n(&value, __ATOMIC_RELAXED) != 1;
        #else
            return 0;
        #endif
        }
    """, ".c")
    conf.Finish()
    if not have_futex_atomic_intrinsics:
        print("libln shm v3 futex synchronization requires GCC/Clang-compatible __atomic intrinsics")
        Exit(1)

env.libln = cenv.SharedLibrary("ln", source=sources, SHLIBVERSION="%s.%s.0" % (libln_major, libln_minor))

Clean(env.libln, Dir("../external"))
Clean(env.libln, Dir("."))

# the install targets
env.InstallVersionedLib("$PREFIX/lib", source=env.libln)
env.InstallHeader ("$PREFIX/include/ln", Glob("include/ln/*"))
env.InstallData   ("$DATADIR/libln", "COPYING.LESSER")
env.InstallData   ("$PREFIX/lib/cmake/liblinks_and_nodes", "cmake/liblinks_and_nodes-config.cmake")

if not GetOption("crosscompiling"):
    SConscript("unittests/SConscript", exports=dict(env=cenv))

build_test = GetOption("test")
if build_test:
    client_env = cenv.Clone()
    ln_scons.link_to_libln(client_env)
    SConscript("tests/%s/SConscript" % build_test, exports=dict(env=client_env))
