GMPINC="$(HOST_GMPINC)"; export GMPINC; \
ISLLIBS="$(HOST_ISLLIBS)"; export ISLLIBS; \
ISLINC="$(HOST_ISLINC)"; export ISLINC; \
+ CODYLIB="$(HOST_CODYLIB)"; export CODYLIB; \
+ CODYLIBINC="$(HOST_CODYLIBINC)"; export CODYLIBINC; \
LIBELFLIBS="$(HOST_LIBELFLIBS)"; export LIBELFLIBS; \
LIBELFINC="$(HOST_LIBELFINC)"; export LIBELFINC; \
XGCC_FLAGS_FOR_TARGET="$(XGCC_FLAGS_FOR_TARGET)"; export XGCC_FLAGS_FOR_TARGET; \
HOST_ISLLIBS = @isllibs@
HOST_ISLINC = @islinc@
+# Where to find libcody
+HOST_CODYLIB = @codylib@
+HOST_CODYLIBINC = @codylibinc@
+
# Where to find libelf
HOST_LIBELFLIBS = @libelflibs@
HOST_LIBELFINC = @libelfinc@
GMPINC="$(HOST_GMPINC)"; export GMPINC; \
ISLLIBS="$(HOST_ISLLIBS)"; export ISLLIBS; \
ISLINC="$(HOST_ISLINC)"; export ISLINC; \
+ CODYLIB="$(HOST_CODYLIB)"; export CODYLIB; \
+ CODYLIBINC="$(HOST_CODYLIBINC)"; export CODYLIBINC; \
LIBELFLIBS="$(HOST_LIBELFLIBS)"; export LIBELFLIBS; \
LIBELFINC="$(HOST_LIBELFINC)"; export LIBELFINC; \
XGCC_FLAGS_FOR_TARGET="$(XGCC_FLAGS_FOR_TARGET)"; export XGCC_FLAGS_FOR_TARGET; \
HOST_ISLLIBS = @isllibs@
HOST_ISLINC = @islinc@
+# Where to find libcody
+HOST_CODYLIB = @codylib@
+HOST_CODYLIBINC = @codylibinc@
+
# Where to find libelf
HOST_LIBELFLIBS = @libelflibs@
HOST_LIBELFINC = @libelfinc@
poststage1_libs
stage1_ldflags
stage1_libs
+codylibinc
+codylib
extra_isl_gmp_configure_flags
extra_mpc_mpfr_configure_flags
extra_mpc_gmp_configure_flags
docdir
oldincludedir
includedir
+runstatedir
localstatedir
sharedstatedir
sysconfdir
with_gmp
with_gmp_include
with_gmp_lib
+with_libcody
+with_libcody_include
+with_libcody_lib
with_stage1_libs
with_static_standard_libraries
with_stage1_ldflags
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE}'
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
- libdir localedir mandir
+ libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
--with-gmp-lib=PATH/lib
--with-gmp-include=PATH specify directory for installed GMP include files
--with-gmp-lib=PATH specify directory for the installed GMP library
+ --with-libcody=PATH specify prefix directory for installed libcody
+ package. Equivalent to
+ --with-libcody-include=PATH/include plus
+ --with-libcody-lib=PATH/lib
+ --with-libcody-include=PATH
+ specify directory for installed libcody include
+ files
+ --with-libcody-lib=PATH specify directory for the installed libcody library
--with-stage1-libs=LIBS libraries for stage1
--with-static-standard-libraries
use -static-libstdc++ and -static-libgcc
+# Specify a location for libcody
+
+# Check whether --with-libcody was given.
+if test "${with_libcody+set}" = set; then :
+ withval=$with_libcody;
+fi
+
+
+# Check whether --with-libcody-include was given.
+if test "${with_libcody_include+set}" = set; then :
+ withval=$with_libcody_include;
+fi
+
+
+# Check whether --with-libcody-lib was given.
+if test "${with_libcody_lib+set}" = set; then :
+ withval=$with_libcody_lib;
+fi
+
+
+if test "x$with_libcody" != x; then
+ codylib="-L$with_libcody/lib"
+ codylibinc="-I$with_libcody/include"
+fi
+if test "x$with_libcody_include" != x; then
+ codylibinc="-I$with_libcody_include"
+fi
+if test "x$with_libcody_lib" != x; then
+ codylib="-L$with_libcody_lib"
+fi
+
+
+
# Libraries to use for stage1 or when not bootstrapping.
# Check whether --with-stage1-libs was given.
AC_SUBST(extra_mpc_mpfr_configure_flags)
AC_SUBST(extra_isl_gmp_configure_flags)
+# Specify a location for libcody
+AC_ARG_WITH(libcody,
+[AS_HELP_STRING([--with-libcody=PATH],
+ [specify prefix directory for installed libcody package.
+ Equivalent to --with-libcody-include=PATH/include
+ plus --with-libcody-lib=PATH/lib])])
+AC_ARG_WITH(libcody-include,
+[AS_HELP_STRING([--with-libcody-include=PATH],
+ [specify directory for installed libcody include files])])
+AC_ARG_WITH(libcody-lib,
+[AS_HELP_STRING([--with-libcody-lib=PATH],
+ [specify directory for the installed libcody library])])
+
+if test "x$with_libcody" != x; then
+ codylib="-L$with_libcody/lib"
+ codylibinc="-I$with_libcody/include"
+fi
+if test "x$with_libcody_include" != x; then
+ codylibinc="-I$with_libcody_include"
+fi
+if test "x$with_libcody_lib" != x; then
+ codylib="-L$with_libcody_lib"
+fi
+AC_SUBST(codylib)
+AC_SUBST(codylibinc)
+
# Libraries to use for stage1 or when not bootstrapping.
AC_ARG_WITH(stage1-libs,
[AS_HELP_STRING([--with-stage1-libs=LIBS], [libraries for stage1])],
ISLLIBS = @ISLLIBS@
ISLINC = @ISLINC@
+# How to find libcody
+CODYLIB = @CODYLIB@ -lcody
+CODYLIBINC = @CODYLIBINC@
+
# Set to 'yes' if the LTO front end is enabled.
enable_lto = @enable_lto@
# and the system's installed libraries.
LIBS = @LIBS@ libcommon.a $(CPPLIB) $(LIBINTL) $(LIBICONV) $(LIBBACKTRACE) \
$(LIBIBERTY) $(LIBDECNUMBER) $(HOST_LIBS)
-BACKENDLIBS = $(ISLLIBS) $(GMPLIBS) $(PLUGINLIBS) $(HOST_LIBS) \
+BACKENDLIBS = $(ISLLIBS) $(GMPLIBS) $(CODYLIB) $(PLUGINLIBS) $(HOST_LIBS) \
$(ZLIB) $(ZSTD_LIB)
# Any system libraries needed just for GNAT.
SYSLIBS = @GNAT_LIBEXC@
# libintl.h will be found in ../intl if we are using the included libintl.
INCLUDES = -I. -I$(@D) -I$(srcdir) -I$(srcdir)/$(@D) \
-I$(srcdir)/../include @INCINTL@ \
- $(CPPINC) $(GMPINC) $(DECNUMINC) $(BACKTRACEINC) \
+ $(CPPINC) $(GMPINC) $(CODYLIBINC) $(DECNUMINC) $(BACKTRACEINC) \
$(ISLINC)
COMPILE.base = $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) -o $@
$(OBJS-libcommon-target) main.o c-family/cppspec.o \
$(COLLECT2_OBJS) $(EXTRA_GCC_OBJS) $(GCOV_OBJS) $(GCOV_DUMP_OBJS) \
$(GCOV_TOOL_OBJS) $(GENGTYPE_OBJS) gcc-ar.o gcc-nm.o gcc-ranlib.o \
- lto-wrapper.o collect-utils.o
+ lto-wrapper.o mapper-client.o mapper-resolver.o mapper-server.o collect-utils.o
# for anything that is shared use the cc1plus profile data, as that
# is likely the most exercised during the build
gnat_install_lib = @gnat_install_lib@
# per-language makefile fragments
--include $(LANG_MAKEFRAGS)
+ifneq ($(LANG_MAKEFRAGS),)
+include $(LANG_MAKEFRAGS)
+endif
# target and host overrides must follow the per-language makefile fragments
# so they can override or augment language-specific variables
# target overrides
--include $(tmake_file)
+ifneq ($(tmake_file),)
+include $(tmake_file)
+endif
# host overrides
--include $(xmake_file)
+ifneq ($(xmake_file),)
+include $(xmake_file)
+endif
# all-tree.def includes all the tree.def files.
all-tree.def: s-alltree; @true
CFLAGS-collect2.o += -DTARGET_MACHINE=\"$(target_noncanonical)\" \
@TARGET_SYSTEM_ROOT_DEFINE@
-LTO_WRAPPER_OBJS = lto-wrapper.o collect-utils.o ggc-none.o
+LTO_WRAPPER_OBJS = lto-wrapper.o mapper-client.o mapper-resolver.o collect-utils.o ggc-none.o
lto-wrapper$(exeext): $(LTO_WRAPPER_OBJS) libcommon-target.a $(LIBDEPS)
+$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o T$@ \
- $(LTO_WRAPPER_OBJS) libcommon-target.a $(LIBS)
+ $(LTO_WRAPPER_OBJS) libcommon-target.a $(CODYLIB) $(LIBS)
mv -f T$@ $@
+#MAPPER_SERVER_OBJS := mapper-server.o mapper-resolver.o
+#mapper-server$(exeext): $(MAPPER_SERVER_OBJS) $(LIBDEPS)
+# +$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
+# $(MAPPER_SERVER_OBJS) version.o $(CODYLIB) $(LIBIBERTY) $(LIBINTL)
+
+MAPPER_SERVER_OBJS := mapper-server.o mapper-resolver.o collect-utils.o
+mapper-server$(exeext): $(MAPPER_SERVER_OBJS) libcommon-target.a $(LIBDEPS)
+ +$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
+ $(MAPPER_SERVER_OBJS) libcommon-target.a version.o $(CODYLIB) $(CPPLIB) $(LIBINTL) $(LIBICONV) $(LIBBACKTRACE) $(LIBIBERTY) $(LIBDECNUMBER) $(HOST_LIBS)
+
+
+#MAPPER_SERVER_OBJS := mapper-server.o mapper-resolver.o collect-utils.o
+#mapper-server$(exeext): $(MAPPER_SERVER_OBJS) libcommon-target.a $(LIBDEPS)
+# +$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
+# $(MAPPER_SERVER_OBJS) libcommon-target.a version.o $(CODYLIB) $(LIBS)
+
# Files used by all variants of C or by the stand-alone pre-processor.
CFLAGS-c-family/c-opts.o += @TARGET_SYSTEM_ROOT_DEFINE@
gcov-dump$(exeext) $(DESTDIR)$(bindir)/$(GCOV_DUMP_INSTALL_NAME)$(exeext); \
fi; \
fi
+ rm -f $(DESTDIR)$(libexecsubdir)/mapper-server$(exeext)
+ $(INSTALL_PROGRAM) mapper-server$(exeext) \
+ $(DESTDIR)$(libexecsubdir)/mapper-server$(exeext)
+
# Install the driver program as $(target_noncanonical)-gcc,
# $(target_noncanonical)-gcc-$(version), and also as gcc if native.
#endif
+/* Define if accept4 provided. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_ACCEPT4
+#endif
+
+
+/* Define if AF_INET6 supported. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AF_INET6
+#endif
+
+
+/* Define if AF_UNIX supported. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AF_UNIX
+#endif
+
+
/* Define if your assembler supports architecture modifiers. */
#ifndef USED_FOR_TARGET
#undef HAVE_AS_ARCHITECTURE_MODIFIERS
#endif
+/* Define if epoll_create, epoll_ctl, epoll_pwait provided. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_EPOLL
+#endif
+
+
+/* Define to 1 if you have the `execv' function. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_EXECV
+#endif
+
+
/* Define to 1 if you have the <ext/hash_map> header file. */
#ifndef USED_FOR_TARGET
#undef HAVE_EXT_HASH_MAP
#endif
+/* Define if inet_ntop provided. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_INET_NTOP
+#endif
+
+
/* Define 0/1 if .init_array/.fini_array sections are available and working.
*/
#ifndef USED_FOR_TARGET
#endif
+/* Define to 1 if you have the `memrchr' function. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_MEMRCHR
+#endif
+
+
/* Define to 1 if you have the `mmap' function. */
#ifndef USED_FOR_TARGET
#undef HAVE_MMAP
#endif
+/* Define to 1 if you have the `posix_fallocate' function. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_POSIX_FALLOCATE
+#endif
+
+
+/* Define if pselect provided. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_PSELECT
+#endif
+
+
/* Define to 1 if you have the `putchar_unlocked' function. */
#ifndef USED_FOR_TARGET
#undef HAVE_PUTCHAR_UNLOCKED
#endif
+/* Define if select provided. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_SELECT
+#endif
+
+
/* Define to 1 if you have the `setlocale' function. */
#ifndef USED_FOR_TARGET
#undef HAVE_SETLOCALE
#endif
+/* Define if <sys/signal.h> defines sighandler_t */
+#ifndef USED_FOR_TARGET
+#undef HAVE_SIGHANDLER_T
+#endif
+
+
/* Define if the system-provided CRTs are present on Solaris. */
#ifndef USED_FOR_TARGET
#undef HAVE_SOLARIS_CRTS
enable_host_shared
enable_plugin
pluginlibs
+CODYLIBINC
+CODYLIB
ISLINC
ISLLIBS
GMPINC
GMPLIBS
GMPINC
ISLLIBS
-ISLINC'
+ISLINC
+CODYLIB
+CODYLIBINC'
# Initialize some variables set by options.
GMPINC How to find GMP include files
ISLLIBS How to link isl
ISLINC How to find isl include files
+ CODYLIB How to link Cody
+ CODYLIBINC How to find Cody include files
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
fi
+ac_fn_cxx_check_type "$LINENO" "sighander_t" "ac_cv_type_sighander_t" "signal.h
+"
+if test "x$ac_cv_type_sighander_t" = xyes; then :
+
+$as_echo "#define HAVE_SIGHANDLER_T 1" >>confdefs.h
+
+fi
+
ac_fn_cxx_check_header_preproc "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h"
fi
+# C++ Modules would like some networking features to provide the mapping
+# server. You can still use modules without them though.
+# The following network-related checks could probably do with some
+# Windows and other non-linux defenses and checking.
+
+# Local socket connectivity wants AF_UNIX networking
+# Check for AF_UNIX networking
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for AF_UNIX" >&5
+$as_echo_n "checking for AF_UNIX... " >&6; }
+if ${ac_cv_af_unix+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+int
+main ()
+{
+
+sockaddr_un un;
+un.sun_family = AF_UNSPEC;
+int fd = socket (AF_UNIX, SOCK_STREAM, 0);
+connect (fd, (sockaddr *)&un, sizeof (un));
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_af_unix=yes
+else
+ ac_cv_af_unix=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_af_unix" >&5
+$as_echo "$ac_cv_af_unix" >&6; }
+if test $ac_cv_af_unix = yes; then
+
+$as_echo "#define HAVE_AF_UNIX 1" >>confdefs.h
+
+fi
+
+# Remote socket connectivity wants AF_INET6 networking
+# Check for AF_INET6 networking
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for AF_INET6" >&5
+$as_echo_n "checking for AF_INET6... " >&6; }
+if ${ac_cv_af_inet6+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+int
+main ()
+{
+
+sockaddr_in6 in6;
+in6.sin6_family = AF_UNSPEC;
+struct addrinfo *addrs = 0;
+struct addrinfo hints;
+hints.ai_flags = 0;
+hints.ai_family = AF_INET6;
+hints.ai_socktype = SOCK_STREAM;
+hints.ai_protocol = 0;
+hints.ai_canonname = 0;
+hints.ai_addr = 0;
+hints.ai_next = 0;
+int e = getaddrinfo ("localhost", 0, &hints, &addrs);
+const char *str = gai_strerror (e);
+freeaddrinfo (addrs);
+int fd = socket (AF_INET6, SOCK_STREAM, 0);
+connect (fd, (sockaddr *)&in6, sizeof (in6));
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_af_inet6=yes
+else
+ ac_cv_af_inet6=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_af_inet6" >&5
+$as_echo "$ac_cv_af_inet6" >&6; }
+if test $ac_cv_af_inet6 = yes; then
+
+$as_echo "#define HAVE_AF_INET6 1" >>confdefs.h
+
+fi
+
+# Efficient server response wants epoll
+# Check for epoll_create, epoll_ctl, epoll_pwait
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for epoll" >&5
+$as_echo_n "checking for epoll... " >&6; }
+if ${ac_cv_epoll+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/epoll.h>
+int
+main ()
+{
+
+int fd = epoll_create (1);
+epoll_event ev;
+ev.events = EPOLLIN;
+ev.data.fd = 0;
+epoll_ctl (fd, EPOLL_CTL_ADD, 0, &ev);
+epoll_pwait (fd, 0, 0, -1, 0);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_epoll=yes
+else
+ ac_cv_epoll=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_epoll" >&5
+$as_echo "$ac_cv_epoll" >&6; }
+if test $ac_cv_epoll = yes; then
+
+$as_echo "#define HAVE_EPOLL 1" >>confdefs.h
+
+fi
+
+# If we can't use epoll, try pselect.
+# Check for pselect
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pselect" >&5
+$as_echo_n "checking for pselect... " >&6; }
+if ${ac_cv_pselect+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/select.h>
+int
+main ()
+{
+
+pselect (0, 0, 0, 0, 0, 0);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_pselect=yes
+else
+ ac_cv_pselect=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pselect" >&5
+$as_echo "$ac_cv_pselect" >&6; }
+if test $ac_cv_pselect = yes; then
+
+$as_echo "#define HAVE_PSELECT 1" >>confdefs.h
+
+fi
+
+# And failing that, use good old select.
+# If we can't even use this, the server is serialized.
+# Check for select
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for select" >&5
+$as_echo_n "checking for select... " >&6; }
+if ${ac_cv_select+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/select.h>
+int
+main ()
+{
+
+select (0, 0, 0, 0, 0);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_select=yes
+else
+ ac_cv_select=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_select" >&5
+$as_echo "$ac_cv_select" >&6; }
+if test $ac_cv_select = yes; then
+
+$as_echo "#define HAVE_SELECT 1" >>confdefs.h
+
+fi
+
+# Avoid some fnctl calls by using accept4, when available.
+# Check for accept4
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for accept4" >&5
+$as_echo_n "checking for accept4... " >&6; }
+if ${ac_cv_accept4+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/socket.h>
+int
+main ()
+{
+
+int err = accept4 (1, 0, 0, SOCK_NONBLOCK);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_accept4=yes
+else
+ ac_cv_accept4=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_accept4" >&5
+$as_echo "$ac_cv_accept4" >&6; }
+if test $ac_cv_accept4 = yes; then
+
+$as_echo "#define HAVE_ACCEPT4 1" >>confdefs.h
+
+fi
+
+# For better server messages, look for a way to stringize network addresses
+# Check for inet_ntop
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntop" >&5
+$as_echo_n "checking for inet_ntop... " >&6; }
+if ${ac_cv_inet_ntop+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+int
+main ()
+{
+
+sockaddr_in6 in6;
+char buf[INET6_ADDRSTRLEN];
+const char *str = inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_inet_ntop=yes
+else
+ ac_cv_inet_ntop=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_inet_ntop" >&5
+$as_echo "$ac_cv_inet_ntop" >&6; }
+if test $ac_cv_inet_ntop = yes; then
+
+$as_echo "#define HAVE_INET_NTOP 1" >>confdefs.h
+
+fi
+
# Restore CFLAGS, CXXFLAGS from before the gcc_AC_NEED_DECLARATIONS tests.
CFLAGS="$saved_CFLAGS"
CXXFLAGS="$saved_CXXFLAGS"
AC_CHECK_TYPE(ssize_t, int)
AC_CHECK_TYPE(caddr_t, char *)
+AC_CHECK_TYPE(sighander_t,
+ AC_DEFINE(HAVE_SIGHANDLER_T, 1,
+ [Define if <sys/signal.h> defines sighandler_t]),
+ ,signal.h)
GCC_AC_FUNC_MMAP_BLACKLIST
[Define if F_SETLKW supported by fcntl.])
fi
+# C++ Modules would like some networking features to provide the mapping
+# server. You can still use modules without them though.
+# The following network-related checks could probably do with some
+# Windows and other non-linux defenses and checking.
+# C++ LTO will take advantage of these networking features too.
+
+# Local socket connectivity wants AF_UNIX networking
+# Check for AF_UNIX networking
+AC_CACHE_CHECK(for AF_UNIX, ac_cv_af_unix, [
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>]],[[
+sockaddr_un un;
+un.sun_family = AF_UNSPEC;
+int fd = socket (AF_UNIX, SOCK_STREAM, 0);
+connect (fd, (sockaddr *)&un, sizeof (un));]])],
+[ac_cv_af_unix=yes],
+[ac_cv_af_unix=no])])
+if test $ac_cv_af_unix = yes; then
+ AC_DEFINE(HAVE_AF_UNIX, 1,
+ [Define if AF_UNIX supported.])
+fi
+
+# Remote socket connectivity wants AF_INET6 networking
+# Check for AF_INET6 networking
+AC_CACHE_CHECK(for AF_INET6, ac_cv_af_inet6, [
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>]],[[
+sockaddr_in6 in6;
+in6.sin6_family = AF_UNSPEC;
+struct addrinfo *addrs = 0;
+struct addrinfo hints;
+hints.ai_flags = 0;
+hints.ai_family = AF_INET6;
+hints.ai_socktype = SOCK_STREAM;
+hints.ai_protocol = 0;
+hints.ai_canonname = 0;
+hints.ai_addr = 0;
+hints.ai_next = 0;
+int e = getaddrinfo ("localhost", 0, &hints, &addrs);
+const char *str = gai_strerror (e);
+freeaddrinfo (addrs);
+int fd = socket (AF_INET6, SOCK_STREAM, 0);
+connect (fd, (sockaddr *)&in6, sizeof (in6));]])],
+[ac_cv_af_inet6=yes],
+[ac_cv_af_inet6=no])])
+if test $ac_cv_af_inet6 = yes; then
+ AC_DEFINE(HAVE_AF_INET6, 1,
+ [Define if AF_INET6 supported.])
+fi
+
+# Efficient server response wants epoll
+# Check for epoll_create, epoll_ctl, epoll_pwait
+AC_CACHE_CHECK(for epoll, ac_cv_epoll, [
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/epoll.h>]],[[
+int fd = epoll_create (1);
+epoll_event ev;
+ev.events = EPOLLIN;
+ev.data.fd = 0;
+epoll_ctl (fd, EPOLL_CTL_ADD, 0, &ev);
+epoll_pwait (fd, 0, 0, -1, 0);]])],
+[ac_cv_epoll=yes],
+[ac_cv_epoll=no])])
+if test $ac_cv_epoll = yes; then
+ AC_DEFINE(HAVE_EPOLL, 1,
+ [Define if epoll_create, epoll_ctl, epoll_pwait provided.])
+fi
+
+# If we can't use epoll, try pselect.
+# Check for pselect
+AC_CACHE_CHECK(for pselect, ac_cv_pselect, [
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/select.h>]],[[
+pselect (0, 0, 0, 0, 0, 0);]])],
+[ac_cv_pselect=yes],
+[ac_cv_pselect=no])])
+if test $ac_cv_pselect = yes; then
+ AC_DEFINE(HAVE_PSELECT, 1,
+ [Define if pselect provided.])
+fi
+
+# And failing that, use good old select.
+# If we can't even use this, the server is serialized.
+# Check for select
+AC_CACHE_CHECK(for select, ac_cv_select, [
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/select.h>]],[[
+select (0, 0, 0, 0, 0);]])],
+[ac_cv_select=yes],
+[ac_cv_select=no])])
+if test $ac_cv_select = yes; then
+ AC_DEFINE(HAVE_SELECT, 1,
+ [Define if select provided.])
+fi
+
+# Avoid some fnctl calls by using accept4, when available.
+# Check for accept4
+AC_CACHE_CHECK(for accept4, ac_cv_accept4, [
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/socket.h>]],[[
+int err = accept4 (1, 0, 0, SOCK_NONBLOCK);]])],
+[ac_cv_accept4=yes],
+[ac_cv_accept4=no])])
+if test $ac_cv_accept4 = yes; then
+ AC_DEFINE(HAVE_ACCEPT4, 1,
+ [Define if accept4 provided.])
+fi
+
+# For better server messages, look for a way to stringize network addresses
+# Check for inet_ntop
+AC_CACHE_CHECK(for inet_ntop, ac_cv_inet_ntop, [
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <arpa/inet.h>
+#include <netinet/in.h>]],[[
+sockaddr_in6 in6;
+char buf[INET6_ADDRSTRLEN];
+const char *str = inet_ntop (AF_INET6, &in6, buf, sizeof (buf));]])],
+[ac_cv_inet_ntop=yes],
+[ac_cv_inet_ntop=no])])
+if test $ac_cv_inet_ntop = yes; then
+ AC_DEFINE(HAVE_INET_NTOP, 1,
+ [Define if inet_ntop provided.])
+fi
+
# Restore CFLAGS, CXXFLAGS from before the gcc_AC_NEED_DECLARATIONS tests.
CFLAGS="$saved_CFLAGS"
CXXFLAGS="$saved_CXXFLAGS"
AC_DEFINE(HAVE_isl, 1, [Define if isl is in use.])
fi
+AC_ARG_VAR(CODYLIB,[How to link Cody])
+AC_ARG_VAR(CODYLIBINC,[How to find Cody include files])
+
GCC_ENABLE_PLUGINS
AC_SUBST(pluginlibs)
AC_SUBST(enable_plugin)
# Note that it would be nice to move the dependency on g++
# into the C++ rule, but that needs a little bit of work
# to do the right thing within all.cross.
-c++: cc1plus$(exeext)
+c++: cc1plus$(exeext) mapper-server$(exeext)
# Tell GNU make to ignore these if they exist.
.PHONY: c++
#include "simple-object.h"
#include "lto-section-names.h"
#include "collect-utils.h"
+#include <stdio.h>
+#include <unistd.h>
+
+#define MAPPER_FOR_GCC 1
+#include "mapper.h"
/* Environment variable, used for passing the names of offload targets from GCC
driver to lto-wrapper. */
const char tool_name[] = "lto-wrapper";
+/********************************************************************/
+
+// FIXME: Put in header somewhere, and maybe verify value
+static const location_t main_source_loc = 32;
+
+/* Our module mapper (created lazily). */
+module_client *mapper;
+
+static module_client *make_mapper (location_t loc);
+inline module_client *get_mapper (location_t loc) {
+ auto *res = mapper;
+ if (!res)
+ res = make_mapper (loc);
+ return res;
+}
+
+/********************************************************************/
+
+/* Create a new mapper connecting to OPTION. */
+
+module_client *
+make_mapper (location_t loc)
+{
+ //const char *option = module_mapper_name;
+ //if (!option)
+ // option = getenv ("CXX_MODULE_MAPPER");
+
+ const char *option = getenv ("CXX_MODULE_MAPPER");
+ fprintf(stderr, "\tCXX_MODULE_MAPPER option: %s\n", option);
+
+ //mapper = module_client::open_module_client(loc, option, &set_cmi_repo, (save_decoded_options[0].opt_index == OPT_SPECIAL_program_name) && save_decoded_options[0].arg != progname ? save_decoded_options[0].arg : nullptr);
+
+ fprintf(stderr, "\tcalling module_client constructor\n");
+ mapper = module_client::open_module_client(loc, option, nullptr, nullptr);
+
+ return mapper;
+}
+
+
/* Delete tempfiles. Called from utils_cleanup. */
void
qsort (ltrans_priorities, nr, sizeof (int) * 2, cmp_priority);
}
+ auto *mapper = get_mapper (main_source_loc);
/* Execute the LTRANS stage for each input file (or prepare a
makefile to invoke this in parallel). */
for (i = 0; i < nr; ++i)
}
else
{
- fork_execute (new_argv[0], CONST_CAST (char **, new_argv),
- true);
+ //fprintf(stderr, "\tRAVI PRINT: %s ", new_argv[0]);
+ mapper->Cork();
+
+ // TODO: better way to figure out the number of arguments?
+ for (j = 1; new_argv[j] != NULL; ++j);
+ fprintf(stderr, "argc: %d\n", j);
+
+ //std::vector<const char*> v_new_argv(new_argv, new_argv + j);
+ //mapper->LTOCompile(v_new_argv);
+ mapper->LTOCompile(new_argv, j);
+ const char **arg_it = new_argv + 1;
+
+ while(*arg_it != NULL)
+ {
+ //fprintf(stderr, "\tRAVI PRINT: %s\n", *arg_it);
+ fprintf(stderr, " \'%s\' ", *arg_it);
+ //mapper->LTOCompile(*arg_it);
+ arg_it++;
+ }
+ ////fprintf(stderr, "\n");
+ mapper->Uncork();
+
+ //fprintf(stderr, "\tRAVI PRINT: %s\n", new_argv[0]);
+ //fork_execute (new_argv[0], CONST_CAST (char **, new_argv),
+ // true);
maybe_unlink (input_name);
}
--- /dev/null
+/* C++ modules. Experimental!
+ Copyright (C) 2017-2020 Free Software Foundation, Inc.
+ Written by Nathan Sidwell <nathan@acm.org> while at FaceBook
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+
+#include "line-map.h"
+#include "diagnostic-core.h"
+#define MAPPER_FOR_GCC 1
+#include "mapper.h"
+
+module_client::module_client (pex_obj *p, int fd_from, int fd_to)
+ : Client (fd_from, fd_to), pex (p)
+{
+}
+
+static module_client *
+spawn_mapper_program (char const **errmsg, std::string &name,
+ char const *full_program_name)
+{
+ /* Split writable at white-space. No space-containing args for
+ you! */
+ // At most every other char could be an argument
+ char **argv = new char *[name.size () / 2 + 2];
+ unsigned arg_no = 0;
+ char *str = new char[name.size ()];
+ memcpy (str, name.c_str () + 1, name.size ());
+
+ for (auto ptr = str; ; ++ptr)
+ {
+ while (*ptr == ' ')
+ ptr++;
+ if (!*ptr)
+ break;
+ argv[arg_no++] = ptr;
+ while (*ptr && *ptr != ' ')
+ ptr++;
+ if (!*ptr)
+ break;
+ *ptr = 0;
+ }
+ argv[arg_no] = nullptr;
+
+ auto *pex = pex_init (PEX_USE_PIPES, progname, NULL);
+ FILE *to = pex_input_pipe (pex, false);
+ name = argv[0];
+ if (!to)
+ *errmsg = "connecting input";
+ else
+ {
+ int flags = PEX_SEARCH;
+
+ if (full_program_name)
+ {
+ /* Prepend the invoking path. */
+ size_t dir_len = progname - full_program_name;
+ std::string argv0;
+ argv0.reserve (dir_len + name.size ());
+ argv0.append (full_program_name, dir_len).append (name);
+ name = std::move (argv0);
+ argv[0] = const_cast <char *> (name.c_str ());
+ flags = 0;
+ }
+ int err;
+ *errmsg = pex_run (pex, flags, argv[0], argv, NULL, NULL, &err);
+ }
+ delete[] str;
+ delete[] argv;
+
+ int fd_from = -1, fd_to = -1;
+ if (!*errmsg)
+ {
+ FILE *from = pex_read_output (pex, false);
+ if (from && (fd_to = dup (fileno (to))) >= 0)
+ fd_from = fileno (from);
+ else
+ *errmsg = "connecting output";
+ fclose (to);
+ }
+
+ if (*errmsg)
+ {
+ pex_free (pex);
+ return nullptr;
+ }
+
+ return new module_client (pex, fd_from, fd_to);
+}
+
+module_client *
+module_client::open_module_client (location_t loc, const char *o,
+ void (*set_repo) (const char *),
+ char const *full_program_name)
+{
+ module_client *c = nullptr;
+ std::string ident;
+ std::string name;
+ char const *errmsg = nullptr;
+
+ if (o && o[0])
+ {
+ /* Maybe a local or ipv6 address. */
+ name = o;
+ auto last = name.find_last_of ('?');
+ if (last != name.npos)
+ {
+ ident = name.substr (last + 1);
+ name.erase (last);
+ }
+
+ if (name.size ())
+ {
+ switch (name[0])
+ {
+ case '<':
+ // <from>to or <>fromto, or <>
+ {
+ int fd_from = -1, fd_to = -1;
+ char const *ptr = name.c_str ();
+ char *eptr;
+
+ fd_from = strtoul (++ptr, &eptr, 0);
+ if (*eptr == '>')
+ {
+ ptr = eptr;
+ fd_to = strtoul (++ptr, &eptr, 0);
+ if (eptr != ptr && ptr == name.c_str () + 1)
+ fd_from = fd_to;
+ }
+
+ if (*eptr)
+ errmsg = "parsing";
+ else
+ {
+ if (name.size () == 2)
+ {
+ fd_from = fileno (stdin);
+ fd_to = fileno (stdout);
+ }
+ c = new module_client (fd_from, fd_to);
+ }
+ }
+ break;
+
+ case '=':
+ // =localsocket
+ {
+ int fd = Cody::OpenLocal (&errmsg, name.c_str () + 1);
+ if (fd >= 0)
+ c = new module_client (fd, fd);
+ }
+ break;
+
+ case '|':
+ // |program and args
+ c = spawn_mapper_program (&errmsg, name, full_program_name);
+ break;
+
+ default:
+ // file or hostname:port
+ {
+ auto colon = name.find_last_of (':');
+ if (colon != name.npos)
+ {
+ char const *cptr = name.c_str () + colon;
+ char *endp;
+ unsigned port = strtoul (cptr + 1, &endp, 10);
+
+ if (port && endp != cptr + 1 && !*endp)
+ {
+ name[colon] = 0;
+ int fd = Cody::OpenInet6 (&errmsg, name.c_str (), port);
+ name[colon] = ':';
+
+ if (fd >= 0)
+ c = new module_client (fd, fd);
+ }
+ }
+
+ }
+ break;
+ }
+ }
+ }
+
+ if (!c)
+ {
+ // Make a default in-process client
+ auto r = new module_resolver ();
+ auto *s = new Cody::Server (r);
+ c = new module_client (s);
+ if (!errmsg && !name.empty ())
+ {
+ int fd = open (name.c_str (), O_RDONLY | O_CLOEXEC);
+ if (fd < 0)
+ errmsg = "opening";
+ else
+ {
+ if (r->read_tuple_file (fd, ident, false))
+ errmsg = "reading";
+
+ close (fd);
+ }
+ }
+ else
+ {
+ r->set_repo ("gcm.cache");
+ r->set_default (true);
+ }
+ }
+
+#ifdef SIGPIPE
+ if (!c->IsDirect ())
+ /* We need to ignore sig pipe for a while. */
+ c->sigpipe = signal (SIGPIPE, SIG_IGN);
+#endif
+
+ if (errmsg)
+ error_at (loc, "failed %s mapper %qs", errmsg, name.c_str ());
+
+ // now wave hello!
+ c->Cork ();
+ c->Connect (std::string ("GCC"), ident);
+ //c->ModuleRepo ();
+ auto packets = c->Uncork ();
+
+ auto &connect = packets[0];
+ if (connect.GetCode () == Cody::Client::PC_CONNECT)
+ ;
+ else if (connect.GetCode () == Cody::Client::PC_ERROR)
+ error_at (loc, "failed mapper handshake %s", connect.GetString ().c_str ());
+
+ //auto &repo = packets[1];
+ //if (repo.GetCode () == Cody::Client::PC_MODULE_REPO)
+ // set_repo (repo.GetString ().c_str ());
+
+ return c;
+}
+
+void
+module_client::close_module_client (location_t loc, module_client *mapper)
+{
+ if (mapper->IsDirect ())
+ {
+ auto *s = mapper->GetServer ();
+ auto *r = s->GetResolver ();
+ delete s;
+ delete r;
+ }
+ else
+ {
+ if (mapper->pex)
+ {
+ int fd_write = mapper->GetFDWrite ();
+ if (fd_write >= 0)
+ close (fd_write);
+
+ int status;
+ pex_get_status (mapper->pex, 1, &status);
+
+ pex_free (mapper->pex);
+ mapper->pex = NULL;
+
+ if (WIFSIGNALED (status))
+ error_at (loc, "mapper died by signal %s",
+ strsignal (WTERMSIG (status)));
+ else if (WIFEXITED (status) && WEXITSTATUS (status) != 0)
+ error_at (loc, "mapper exit status %d",
+ WEXITSTATUS (status));
+ }
+ else
+ {
+ int fd_read = mapper->GetFDRead ();
+ close (fd_read);
+ }
+
+#ifdef SIGPIPE
+ // Restore sigpipe
+ if (mapper->sigpipe != SIG_IGN)
+ signal (SIGPIPE, mapper->sigpipe);
+#endif
+ }
+
+ delete mapper;
+}
--- /dev/null
+/* C++ modules. Experimental! -*- c++-mode -*-
+ Copyright (C) 2017-2020 Free Software Foundation, Inc.
+ Written by Nathan Sidwell <nathan@acm.org> while at FaceBook
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "mapper.h"
+// C++
+#include <algorithm>
+// C
+#include <cstring>
+// OS
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "collect-utils.h"
+
+module_resolver::module_resolver (bool def)
+ : provide_default (def)
+{
+}
+
+module_resolver::~module_resolver ()
+{
+ if (fd_repo >= 0)
+ close (fd_repo);
+}
+
+bool
+module_resolver::set_repo (std::string &&r, bool force)
+{
+ if (force || repo.empty ())
+ {
+ repo = std::move (r);
+ force = true;
+ }
+ return force;
+}
+
+bool
+module_resolver::add_mapping (std::string &&module, std::string &&file,
+ bool force)
+{
+ auto res = map.emplace (std::move (module), std::move (file));
+ if (res.second)
+ force = true;
+ else if (force)
+ res.first->second = std::move (file);
+
+ return force;
+}
+
+int
+module_resolver::read_tuple_file (int fd, char const *prefix, bool force)
+{
+ struct stat stat;
+ if (fstat (fd, &stat) < 0)
+ return -errno;
+
+ // Just Map the file, we're gonna read all of it, so no need for
+ // line buffering
+ void *buffer = mmap (nullptr, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (buffer == MAP_FAILED)
+ return -errno;
+
+ size_t prefix_len = prefix ? strlen (prefix) : 0;
+ unsigned lineno = 0;
+
+ for (char const *begin = reinterpret_cast <char const *> (buffer),
+ *end = begin + stat.st_size, *eol;
+ begin != end; begin = eol + 1)
+ {
+ lineno++;
+ eol = std::find (begin, end, '\n');
+ if (eol == end)
+ // last line has no \n, ignore the line, you lose
+ break;
+
+ auto *pos = begin;
+ bool pfx_search = prefix_len != 0;
+
+ pfx_search:
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+
+ auto *space = pos;
+ while (*space != '\n' && *space != ' ' && *space != '\t')
+ space++;
+
+ if (pos == space)
+ // at end of line, nothing here
+ continue;
+
+ if (pfx_search)
+ {
+ if (size_t (space - pos) == prefix_len
+ && std::equal (pos, space, prefix))
+ pfx_search = false;
+ pos = space;
+ goto pfx_search;
+ }
+
+ std::string module (pos, space);
+ while (*space == ' ' || *space == '\t')
+ space++;
+ std::string file (space, eol);
+
+ if (module[0] == '$')
+ {
+ if (module == "$root")
+ set_repo (std::move (file));
+ else
+ return lineno;
+ }
+ else
+ {
+ if (file.empty ())
+ file = GetCMIName (module);
+ add_mapping (std::move (module), std::move (file), force);
+ }
+ }
+
+ munmap (buffer, stat.st_size);
+
+ return 0;
+}
+
+char const *
+module_resolver::GetCMISuffix ()
+{
+ return "gcm";
+}
+
+module_resolver *
+module_resolver::ConnectRequest (Cody::Server *s, unsigned version,
+ std::string &a, std::string &i)
+{
+ if (!version || version > Cody::Version)
+ s->ErrorResponse ("version mismatch");
+ else if (a != "GCC")
+ // Refuse anything but GCC
+ ErrorResponse (s, std::string ("only GCC supported"));
+ else if (!ident.empty () && ident != i)
+ // Failed ident check
+ ErrorResponse (s, std::string ("bad ident"));
+ else
+ // Success!
+ s->ConnectResponse ("gcc");
+
+ return this;
+}
+
+int
+module_resolver::ModuleRepoRequest (Cody::Server *s)
+{
+ s->ModuleRepoResponse (repo);
+ return 0;
+}
+
+int
+module_resolver::cmi_response (Cody::Server *s, std::string &module)
+{
+ auto iter = map.find (module);
+ if (iter == map.end ())
+ {
+ std::string file;
+ if (provide_default)
+ file = std::move (GetCMIName (module));
+ auto res = map.emplace (module, file);
+ iter = res.first;
+ }
+
+ if (iter->second.empty ())
+ s->ErrorResponse ("no such module");
+ else
+ s->ModuleCMIResponse (iter->second);
+
+ return 0;
+}
+
+int
+module_resolver::ModuleExportRequest (Cody::Server *s, std::string &module)
+{
+ return cmi_response (s, module);
+}
+
+int
+module_resolver::ModuleImportRequest (Cody::Server *s, std::string &module)
+{
+ return cmi_response (s, module);
+}
+
+int
+module_resolver::IncludeTranslateRequest (Cody::Server *s,
+ std::string &include)
+{
+ auto iter = map.find (include);
+ if (iter == map.end ())
+ {
+ // Not found, look for it
+ if (fd_repo == -1 && !repo.empty ())
+ {
+ fd_repo = open (repo.c_str (), O_RDONLY | O_CLOEXEC | O_DIRECTORY);
+ if (fd_repo < 0)
+ fd_repo = -2;
+ }
+
+ if (fd_repo >= 0 || repo.empty ())
+ {
+ auto file = GetCMIName (include);
+ struct stat statbuf;
+ if (fstatat (repo.empty () ? AT_FDCWD : fd_repo,
+ file.c_str (), &statbuf, 0) < 0
+ || !S_ISREG (statbuf.st_mode))
+ // Mark as not present
+ file.clear ();
+ auto res = map.emplace (include, file);
+ iter = res.first;
+ }
+ }
+
+ if (iter == map.end () || iter->second.empty ())
+ s->IncludeTranslateResponse (false);
+ else
+ s->ModuleCMIResponse (iter->second);
+
+ return 0;
+}
+
+int module_resolver::LTOCompileRequest (Cody::Server *s, std::vector<std::string> &args) {
+ char **new_argv = (char **)malloc((args.size()) * sizeof(char *));
+ new_argv[args.size()-1] = NULL;
+
+ int i = 0;
+ for (std::vector<std::string>::iterator arg = args.begin() ; arg != args.end(); ++arg, ++i) {
+
+ // ignore "LTO-COMPILE"
+ if(i == 0) continue;
+ //new_argv[i++] = (char *)malloc(args[i].length() * sizeof(char));
+
+ // TODO: type safety
+ new_argv[i-1] = (char *)(*arg).c_str();
+ //fprintf(stderr, "*arg[?] = %s\n", (*arg).c_str());
+ //fprintf(stderr, "*new_argv[%d] = %s\n", i-1, new_argv[i-1]);
+ }
+
+ //fprintf(stderr, "\tcalling fork_execute\n");
+ fork_execute (new_argv[0], new_argv, true);
+
+ // TODO: send back a compile status response
+ //s->LTOResponse();
+ return 0;
+}
+
--- /dev/null
+/* C++ modules. Experimental!
+ Copyright (C) 2018-2020 Free Software Foundation, Inc.
+ Written by Nathan Sidwell <nathan@acm.org> while at FaceBook
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "mapper.h"
+
+// C++
+#include <set>
+#include <vector>
+// GCC
+#define INCLUDE_VECTOR
+#define INCLUDE_MAP
+#define INCLUDE_SET
+
+// Network
+/* Include network stuff first. Excitingly OSX10.14 uses bcmp here, which
+ we poison later! */
+#if defined (HAVE_AF_UNIX) || defined (HAVE_AF_INET6)
+/* socket, bind, listen, accept{4} */
+# define NETWORKING 1
+# include <sys/socket.h>
+# ifdef HAVE_AF_UNIX
+/* sockaddr_un */
+# include <sys/un.h>
+# endif
+# include <netinet/in.h>
+# ifdef HAVE_AF_INET6
+/* sockaddr_in6, getaddrinfo, freeaddrinfo, gai_sterror, ntohs, htons. */
+# include <netdb.h>
+# endif
+#ifdef HAVE_INET_NTOP
+/* inet_ntop. */
+#include <arpa/inet.h>
+#endif
+#endif
+#ifndef HAVE_AF_INET6
+# define gai_strerror(X) ""
+#endif
+
+// Excitingly Darwin uses bcmp in its network headers, and we poison
+// that in our setup.
+#include "system.h"
+#include "version.h"
+#include "intl.h"
+#include <getopt.h>
+
+// Select or epoll
+#ifdef NETWORKING
+#ifdef HAVE_EPOLL
+/* epoll_create, epoll_ctl, epoll_pwait */
+#include <sys/epoll.h>
+#endif
+#if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
+/* pselect or select */
+#include <sys/select.h>
+#endif
+#endif
+
+#ifndef HAVE_SIGHANDLER_T
+typedef void (*sighandler_t) (int);
+#endif
+
+struct netmask {
+ in6_addr addr;
+ unsigned bits;
+
+ netmask (const in6_addr &a, unsigned b)
+ {
+ if (b > sizeof (in6_addr) * 8)
+ b = sizeof (in6_addr) * 8;
+ bits = b;
+ unsigned byte = (b + 7) / 8;
+ unsigned ix = 0;
+ for (ix = 0; ix < byte; ix++)
+ addr.s6_addr[ix] = a.s6_addr[ix];
+ for (; ix != sizeof (in6_addr); ix++)
+ addr.s6_addr[ix] = 0;
+ if (b & 3)
+ addr.s6_addr[b/7] &= (255 << 8) >> (b & 3);
+ }
+
+ bool includes (const in6_addr &a) const
+ {
+ unsigned byte = bits / 8;
+ for (unsigned ix = 0; ix != byte; ix++)
+ if (addr.s6_addr[ix] != a.s6_addr[ix])
+ return false;
+ if (bits & 3)
+ if ((addr.s6_addr[byte] ^ a.s6_addr[byte]) >> (8 - (bits & 3)))
+ return false;
+ return true;
+ }
+};
+
+/* Netmask comparison. */
+struct netmask_cmp {
+ bool operator() (const netmask &a, const netmask &b) const
+ {
+ if (a.bits != b.bits)
+ return a.bits < b.bits;
+ for (unsigned ix = 0; ix != sizeof (in6_addr); ix++)
+ if (a.addr.s6_addr[ix] != b.addr.s6_addr[ix])
+ return a.addr.s6_addr[ix] < b.addr.s6_addr[ix];
+ return false;
+ }
+};
+
+typedef std::set<netmask, netmask_cmp> netmask_set_t;
+typedef std::vector<netmask> netmask_vec_t;
+
+const char *progname;
+
+/* Speak thoughts out loud. */
+static bool flag_noisy = false;
+
+/* One and done. */
+static bool flag_one = false;
+
+/* Serialize connections. */
+static bool flag_sequential = false;
+
+/* Fallback to default if map file is unrewarding. */
+static bool flag_fallback = false;
+
+/* Root binary directory. */
+static const char *flag_root = "gcm.cache";
+
+static netmask_set_t netmask_set;
+
+static netmask_vec_t accept_addrs;
+
+/* Strip out the source directory from FILE. */
+
+static const char *
+trim_src_file (const char *file)
+{
+ static const char me[] = __FILE__;
+ unsigned pos = 0;
+
+ while (file[pos] == me[pos] && me[pos])
+ pos++;
+ while (pos && !IS_DIR_SEPARATOR (me[pos-1]))
+ pos--;
+
+ return file + pos;
+}
+
+/* TODO: Delete tempfiles. Called from utils_cleanup. */
+
+void tool_cleanup (bool) {
+
+}
+
+// TODO: undefined reference?
+unsigned int input_location=0;
+void fatal_error (unsigned int f, const char *str, ...) {
+
+}
+
+/* Die screaming. */
+
+void ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD
+internal_error (const char *fmt, ...)
+{
+ fprintf (stderr, "%s:Internal error ", progname);
+ va_list args;
+
+ va_start (args, fmt);
+ vfprintf (stderr, fmt, args);
+ va_end (args);
+ fprintf (stderr, "\n");
+
+ exit (FATAL_EXIT_CODE);
+}
+
+/* Hooked to from gcc_assert & gcc_unreachable. */
+
+void ATTRIBUTE_NORETURN ATTRIBUTE_COLD
+fancy_abort (const char *file, int line, const char *func)
+{
+ internal_error ("in %s, at %s:%d", func, trim_src_file (file), line);
+}
+
+/* Exploded on a signal. */
+
+static void ATTRIBUTE_NORETURN ATTRIBUTE_COLD
+crash_signal (int sig)
+{
+ signal (sig, SIG_DFL);
+ internal_error ("signal %s", strsignal (sig));
+}
+
+/* A fatal error of some kind. */
+
+static void ATTRIBUTE_NORETURN ATTRIBUTE_COLD ATTRIBUTE_PRINTF_1
+error (const char *msg, ...)
+{
+ fprintf (stderr, "%s:error: ", progname);
+ va_list args;
+
+ va_start (args, msg);
+ vfprintf (stderr, msg, args);
+ va_end (args);
+ fprintf (stderr, "\n");
+
+ exit (1);
+}
+
+/* Progress messages to the user. */
+static bool ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD
+noisy (const char *fmt, ...)
+{
+ fprintf (stderr, "%s:", progname);
+ va_list args;
+ va_start (args, fmt);
+ vfprintf (stderr, fmt, args);
+ va_end (args);
+ fprintf (stderr, "\n");
+
+ return false;
+}
+
+/* More messages to the user. */
+
+static void ATTRIBUTE_PRINTF_2
+fnotice (FILE *file, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start (args, fmt);
+ vfprintf (file, _(fmt), args);
+ va_end (args);
+}
+
+static void ATTRIBUTE_NORETURN
+print_usage (int error_p)
+{
+ FILE *file = error_p ? stderr : stdout;
+ int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
+
+ fnotice (file, "Usage: cxx-mapper [OPTION...] [CONNECTION] [MAPPINGS...] \n\n");
+ fnotice (file, "C++ Module Mapper.\n\n");
+ fnotice (file, " -a, --accept Netmask to accept from\n");
+ fnotice (file, " -f, --fallback Use fallback for missing mappings\n");
+ fnotice (file, " -h, --help Print this help, then exit\n");
+ fnotice (file, " -n, --noisy Print progress messages\n");
+ fnotice (file, " -1, --one One connection and then exit\n");
+ fnotice (file, " -r, --root DIR Root compiled module directory\n");
+ fnotice (file, " -s, --sequential Process connections sequentially\n");
+ fnotice (file, " -v, --version Print version number, then exit\n");
+ fnotice (file, "Send SIGTERM(%d) to terminate\n", SIGTERM);
+ fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
+ bug_report_url);
+ exit (status);
+}
+
+/* Print version information and exit. */
+
+static void ATTRIBUTE_NORETURN
+print_version (void)
+{
+ fnotice (stdout, "cxx-mapper %s%s\n", pkgversion_string, version_string);
+ fprintf (stdout, "Copyright %s 2018-2020 Free Software Foundation, Inc.\n",
+ _("(C)"));
+ fnotice (stdout,
+ _("This is free software; see the source for copying conditions.\n"
+ "There is NO warranty; not even for MERCHANTABILITY or \n"
+ "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
+ exit (SUCCESS_EXIT_CODE);
+}
+
+/* ARG is a netmask to accept from. Add it to the table. Return
+ false if we fail to resolve it. */
+
+static bool
+accept_from (char *arg)
+{
+ bool ok = true;
+#if HAVE_AF_INET6
+ unsigned bits = sizeof (in6_addr) * 8;
+ char *slash = strrchr (arg, '/');
+ if (slash)
+ {
+ *slash = 0;
+ if (slash[1])
+ {
+ char *endp;
+ bits = strtoul (slash + 1, &endp, 0);
+ }
+ }
+
+ addrinfo hints;
+
+ hints.ai_flags = AI_NUMERICSERV;
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ hints.ai_addrlen = 0;
+ hints.ai_addr = NULL;
+ hints.ai_canonname = NULL;
+ hints.ai_next = NULL;
+
+ struct addrinfo *addrs = NULL;
+ if (int e = getaddrinfo (slash == arg ? NULL : arg, "0", &hints, &addrs))
+ {
+ noisy ("cannot resolve '%s': %s", arg, gai_strerror (e));
+ ok = false;
+ }
+ else
+ for (addrinfo *next = addrs; next; next = next->ai_next)
+ if (next->ai_family == AF_INET6)
+ {
+ netmask mask (((const sockaddr_in6 *)next->ai_addr)->sin6_addr, bits);
+ netmask_set.insert (mask);
+ }
+ freeaddrinfo (addrs);
+#endif
+ return ok;
+}
+
+/* Process args, return index to first non-arg. */
+
+static int
+process_args (int argc, char **argv)
+{
+ static const struct option options[] =
+ {
+ { "accept", required_argument, NULL, 'a' },
+ { "fallback",no_argument, NULL, 'f' },
+ { "help", no_argument, NULL, 'h' },
+ { "noisy", no_argument, NULL, 'n' },
+ { "one", no_argument, NULL, '1' },
+ { "root", required_argument, NULL, 'r' },
+ { "sequential", no_argument, NULL, 's' },
+ { "version", no_argument, NULL, 'v' },
+ { 0, 0, 0, 0 }
+ };
+ int opt;
+ bool bad_accept = false;
+ const char *opts = "a:fhn1r:sv";
+ while ((opt = getopt_long (argc, argv, opts, options, NULL)) != -1)
+ {
+ switch (opt)
+ {
+ case 'a':
+ if (!accept_from (optarg))
+ bad_accept = true;
+ break;
+ case 'f':
+ flag_fallback = true;
+ break;
+ case 'h':
+ print_usage (false);
+ /* print_usage will exit. */
+ case 'n':
+ flag_noisy = true;
+ break;
+ case '1':
+ flag_one = true;
+ break;
+ case 'r':
+ flag_root = optarg;
+ break;
+ case 's':
+ flag_sequential = true;
+ break;
+ case 'v':
+ print_version ();
+ /* print_version will exit. */
+ default:
+ print_usage (true);
+ /* print_usage will exit. */
+ }
+ }
+
+ if (bad_accept)
+ error ("failed to resolve all accept addresses");
+
+ return optind;
+}
+
+/* Manipulate the EPOLL state, or do nothing, if there is epoll. */
+
+#ifdef HAVE_EPOLL
+static inline void
+do_epoll_ctl (int epoll_fd, int code, int event, int fd, unsigned data)
+{
+ epoll_event ev;
+ ev.events = event;
+ ev.data.u32 = data;
+ if (epoll_ctl (epoll_fd, code, fd, &ev))
+ {
+ noisy ("epoll_ctl error:%s", xstrerror (errno));
+ gcc_unreachable ();
+ }
+}
+#define my_epoll_ctl(EFD,C,EV,FD,CL) \
+ ((EFD) >= 0 ? do_epoll_ctl (EFD,C,EV,FD,CL) : (void)0)
+#else
+#define my_epoll_ctl(EFD,C,EV,FD,CL) ((void)(EFD), (void)(FD), (void)(CL))
+#endif
+
+#ifdef NETWORKING
+/* We increment this to tell the server to shut down. */
+static volatile int term = false;
+static volatile int kill_sock_fd = -1;
+#if !defined (HAVE_PSELECT) && defined (HAVE_SELECT)
+static int term_pipe[2] = {-1, -1};
+#else
+#define term_pipe ((int *)NULL)
+#endif
+
+/* A terminate signal. Shutdown gracefully. */
+
+static void
+term_signal (int sig)
+{
+ signal (sig, term_signal);
+ term = term + 1;
+ if (term_pipe && term_pipe[1] >= 0)
+ write (term_pipe[1], &term_pipe[1], 1);
+}
+
+/* A kill signal. Shutdown immediately. */
+
+static void
+kill_signal (int sig)
+{
+ signal (sig, SIG_DFL);
+ int sock_fd = kill_sock_fd;
+ if (sock_fd >= 0)
+ close (sock_fd);
+ exit (2);
+}
+
+bool process_server (Cody::Server *server, unsigned slot, int epoll_fd)
+{
+ switch (server->GetDirection ())
+ {
+ case Cody::Server::READING:
+ if (int err = server->Read ())
+ return !(err == EINTR || err == EAGAIN);
+ server->ProcessRequests ();
+ server->PrepareToWrite ();
+ break;
+
+ case Cody::Server::WRITING:
+ if (int err = server->Write ())
+ return !(err == EINTR || err == EAGAIN);
+ server->PrepareToRead ();
+ break;
+
+ default:
+ // We should never get here
+ return true;
+ }
+
+ // We've changed direction, so update epoll
+ gcc_assert (server->GetFDRead () == server->GetFDWrite ());
+ my_epoll_ctl (epoll_fd, EPOLL_CTL_MOD,
+ server->GetDirection () == Cody::Server::READING
+ ? EPOLLIN : EPOLLOUT, server->GetFDRead (), slot + 1);
+
+ return false;
+}
+
+void close_server (Cody::Server *server, int epoll_fd)
+{
+ my_epoll_ctl (epoll_fd, EPOLL_CTL_DEL, EPOLLIN, server->GetFDRead (), 0);
+
+ close (server->GetFDRead ());
+
+ delete server;
+}
+
+int open_server (bool ip6, int sock_fd)
+{
+ sockaddr_in6 addr;
+ socklen_t addr_len = sizeof (addr);
+
+#ifdef HAVE_ACCEPT4
+ int client_fd = accept4 (sock_fd, ip6 ? (sockaddr *)&addr : nullptr,
+ &addr_len, SOCK_NONBLOCK);
+#else
+ int client_fd = accept (sock_fd, ip6 ? (sockaddr *)&addr : nullptr, &addr_len);
+#endif
+ if (client_fd < 0)
+ {
+ error ("cannot accept: %s", xstrerror (errno));
+ flag_one = true;
+ }
+ else if (ip6)
+ {
+ const char *str = NULL;
+#if HAVE_INET_NTOP
+ char name[INET6_ADDRSTRLEN];
+ str = inet_ntop (addr.sin6_family, &addr.sin6_addr, name, sizeof (name));
+#endif
+ if (!accept_addrs.empty ())
+ {
+ netmask_vec_t::iterator e = accept_addrs.end ();
+ for (netmask_vec_t::iterator i = accept_addrs.begin ();
+ i != e; ++i)
+ if (i->includes (addr.sin6_addr))
+ goto present;
+ close (client_fd);
+ client_fd = -1;
+ noisy ("Rejecting connection from disallowed source '%s'",
+ str ? str : "");
+ present:;
+ }
+ if (client_fd >= 0)
+ flag_noisy && noisy ("Accepting connection from '%s'", str ? str : "");
+ }
+
+ return client_fd;
+}
+
+/* A server listening on bound socket SOCK_FD. */
+
+static void
+server (bool ipv6, int sock_fd, module_resolver *resolver)
+{
+ int epoll_fd = -1;
+
+ signal (SIGTERM, term_signal);
+#ifdef HAVE_EPOLL
+ epoll_fd = epoll_create (1);
+#endif
+ if (epoll_fd >= 0)
+ my_epoll_ctl (epoll_fd, EPOLL_CTL_ADD, EPOLLIN, sock_fd, 0);
+
+#if defined (HAVE_EPOLL) || defined (HAVE_PSELECT) || defined (HAVE_SELECT)
+ sigset_t mask;
+ {
+ sigset_t block;
+ sigemptyset (&block);
+ sigaddset (&block, SIGTERM);
+ sigprocmask (SIG_BLOCK, &block, &mask);
+ }
+#endif
+
+#ifdef HAVE_EPOLL
+ const unsigned max_events = 20;
+ epoll_event events[max_events];
+#endif
+#if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
+ fd_set readers, writers;
+#endif
+ if (term_pipe)
+ pipe (term_pipe);
+
+ // We need stable references to servers, so this array can contain nulls
+ std::vector<Cody::Server *> connections;
+ unsigned live = 0;
+ while (sock_fd >= 0 || live)
+ {
+ /* Wait for one or more events. */
+ bool eintr = false;
+ int event_count;
+
+ if (epoll_fd >= 0)
+ {
+#ifdef HAVE_EPOLL
+ event_count = epoll_pwait (epoll_fd, events, max_events, -1, &mask);
+#endif
+ }
+ else
+ {
+#if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
+ FD_ZERO (&readers);
+ FD_ZERO (&writers);
+
+ unsigned limit = 0;
+ if (sock_fd >= 0
+ && !(term || (live && (flag_one || flag_sequential))))
+ {
+ FD_SET (sock_fd, &readers);
+ limit = sock_fd + 1;
+ }
+
+ if (term_pipe && term_pipe[0] >= 0)
+ {
+ FD_SET (term_pipe[0], &readers);
+ if (unsigned (term_pipe[0]) >= limit)
+ limit = term_pipe[0] + 1;
+ }
+
+ for (auto iter = connections.begin ();
+ iter != connections.end (); ++iter)
+ if (auto *server = *iter)
+ {
+ int fd = -1;
+ switch (server->GetDirection ())
+ {
+ case Cody::Server::READING:
+ fd = server->GetFDRead ();
+ FD_SET (fd, &readers);
+ break;
+ case Cody::Server::WRITING:
+ fd = server->GetFDWrite ();
+ FD_SET (fd, &writers);
+ break;
+ default:
+ break;
+ }
+
+ if (fd >= 0 && limit <= unsigned (fd))
+ limit = fd + 1;
+ }
+
+#ifdef HAVE_PSELECT
+ event_count = pselect (limit, &readers, &writers, NULL, NULL, &mask);
+#else
+ event_count = select (limit, &readers, &writers, NULL, NULL);
+#endif
+ if (term_pipe && FD_ISSET (term_pipe[0], &readers))
+ {
+ /* Fake up an interrupted system call. */
+ event_count = -1;
+ errno = EINTR;
+ }
+#endif
+ }
+
+ if (event_count < 0)
+ {
+ // Error in waiting
+ if (errno == EINTR)
+ {
+ flag_noisy && noisy ("Interrupted wait");
+ eintr = true;
+ }
+ else
+ error ("cannot %s: %s", epoll_fd >= 0 ? "epoll_wait"
+#ifdef HAVE_PSELECT
+ : "pselect",
+#else
+ : "select",
+#endif
+ xstrerror (errno));
+ event_count = 0;
+ }
+
+ auto iter = connections.begin ();
+ while (event_count--)
+ {
+ // Process an event
+ int active = -2;
+
+ if (epoll_fd >= 0)
+ {
+#ifdef HAVE_EPOLL
+ /* See PR c++/88664 for why a temporary is used. */
+ unsigned data = events[event_count].data.u32;
+ active = int (data) - 1;
+#endif
+ }
+ else
+ {
+ for (; iter != connections.end (); ++iter)
+ if (auto *server = *iter)
+ {
+ bool found = false;
+ switch (server->GetDirection ())
+ {
+#if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
+ case Cody::Server::READING:
+ found = FD_ISSET (server->GetFDRead (), &readers);
+ break;
+ case Cody::Server::WRITING:
+ found = FD_ISSET (server->GetFDWrite (), &writers);
+ break;
+#endif
+ default:
+ break;
+ }
+
+ if (found)
+ {
+ active = iter - connections.begin ();
+ ++iter;
+ break;
+ }
+ }
+
+ if (active < 0 && sock_fd >= 0 && FD_ISSET (sock_fd, &readers))
+ active = -1;
+ }
+
+ if (active >= 0)
+ {
+ // Do the action
+ auto *server = connections[active];
+ if (process_server (server, active, epoll_fd))
+ {
+ connections[active] = nullptr;
+ close_server (server, epoll_fd);
+ live--;
+ if (flag_sequential)
+ my_epoll_ctl (epoll_fd, EPOLL_CTL_ADD, EPOLLIN, sock_fd, 0);
+ }
+ }
+ else if (active == -1 && !eintr)
+ {
+ // New connection
+ int fd = open_server (ipv6, sock_fd);
+ if (fd >= 0)
+ {
+#if !defined (HAVE_ACCEPT4) \
+ && (defined (HAVE_EPOLL) || defined (HAVE_PSELECT) || defined (HAVE_SELECT))
+ int flags = fcntl (fd, F_GETFL, 0);
+ fcntl (fd, F_SETFL, flags | O_NONBLOCK);
+#endif
+ auto *server = new Cody::Server (resolver, fd);
+
+ unsigned slot = connections.size ();
+ if (live == slot)
+ connections.push_back (server);
+ else
+ for (auto iter = connections.begin (); ; ++iter)
+ if (!*iter)
+ {
+ *iter = server;
+ slot = iter - connections.begin ();
+ break;
+ }
+ live++;
+ my_epoll_ctl (epoll_fd, EPOLL_CTL_ADD, EPOLLIN, fd, slot + 1);
+ }
+ }
+
+ if (sock_fd >= 0
+ && (term || (live && (flag_one || flag_sequential))))
+ {
+ /* Stop paying attention to sock_fd. */
+ my_epoll_ctl (epoll_fd, EPOLL_CTL_DEL, EPOLLIN, sock_fd, 0);
+ if (flag_one || term)
+ {
+ close (sock_fd);
+ sock_fd = -1;
+ }
+ }
+ }
+ }
+#if defined (HAVE_EPOLL) || defined (HAVE_PSELECT) || defined (HAVE_SELECT)
+ /* Restore the signal mask. */
+ sigprocmask (SIG_SETMASK, &mask, NULL);
+#endif
+
+ gcc_assert (sock_fd < 0);
+ if (epoll_fd >= 0)
+ close (epoll_fd);
+
+ if (term_pipe && term_pipe[0] >= 0)
+ {
+ close (term_pipe[0]);
+ close (term_pipe[1]);
+ }
+}
+
+#if 0
+
+
+ if (eintr)
+ flag_noisy && noisy ("Interrupted wait");
+
+
+ if (sock_fd >= 0 && (term || flag_one || flag_sequential))
+ {
+ /* Stop paying attention to sock_fd. */
+ my_epoll_ctl (epoll_fd, EPOLL_CTL_DEL, EPOLLIN, sock_fd, NULL);
+ if (flag_one || term)
+ {
+ close (sock_fd);
+ sock_fd = -1;
+ }
+ }
+ }
+
+#if defined (HAVE_EPOLL) || defined (HAVE_PSELECT) || defined (HAVE_SELECT)
+ /* Restore the signal mask. */
+ sigprocmask (SIG_SETMASK, &mask, NULL);
+#endif
+
+ gcc_assert (sock_fd < 0);
+ if (epoll_fd >= 0)
+ close (epoll_fd);
+
+ if (term_pipe && term_pipe[0] >= 0)
+ {
+ close (term_pipe[0]);
+ close (term_pipe[1]);
+ }
+}
+#endif
+
+#endif
+
+static int maybe_parse_socket (std::string &option, module_resolver *r)
+{
+ /* Local or ipv6 address. */
+ auto last = option.find_last_of ('?');
+ if (last != option.npos)
+ {
+ r->set_ident (option.c_str () + last + 1);
+ option.erase (last);
+ }
+ int fd = -2;
+ char const *errmsg = nullptr;
+
+ /* Does it look like a socket? */
+ if (option[0] == '=')
+ /* A local socket. */
+ fd = Cody::ListenLocal (&errmsg, option.c_str () + 1);
+ else
+ {
+ auto colon = option.find_last_of (':');
+ if (colon != option.npos)
+ {
+ /* Try a hostname:port address. */
+ char const *cptr = option.c_str () + colon;
+ char *endp;
+ unsigned port = strtoul (cptr + 1, &endp, 10);
+
+ if (port && endp != cptr + 1 && !*endp)
+ {
+ /* Ends in ':number', treat as ipv6 domain socket. */
+ option.erase (colon);
+ fd = Cody::ListenInet6 (&errmsg, option.c_str (), port);
+ }
+ }
+ }
+
+ if (errmsg)
+ error ("failed to open socket: %s", errmsg);
+
+ return fd;
+}
+
+int
+main (int argc, char *argv[])
+{
+ const char *p = argv[0] + strlen (argv[0]);
+ while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
+ --p;
+ progname = p;
+
+ xmalloc_set_program_name (progname);
+
+#ifdef SIGSEGV
+ signal (SIGSEGV, crash_signal);
+#endif
+#ifdef SIGILL
+ signal (SIGILL, crash_signal);
+#endif
+#ifdef SIGBUS
+ signal (SIGBUS, crash_signal);
+#endif
+#ifdef SIGABRT
+ signal (SIGABRT, crash_signal);
+#endif
+#ifdef SIGFPE
+ signal (SIGFPE, crash_signal);
+#endif
+#ifdef SIGPIPE
+ /* Ignore sigpipe, so read/write get an error. */
+ signal (SIGPIPE, SIG_IGN);
+#endif
+#ifdef SIGINT
+ signal (SIGINT, kill_signal);
+#endif
+
+ int argno = process_args (argc, argv);
+
+ module_resolver r;
+ if (flag_root)
+ r.set_repo (flag_root);
+
+ std::string name;
+ int sock_fd = -1; /* Socket fd, otherwise stdin/stdout. */
+
+ if (argno != argc)
+ {
+ name = argv[argno];
+ sock_fd = maybe_parse_socket (name, &r);
+ if (!name.empty ())
+ argno++;
+ }
+
+ if (argno != argc)
+ for (; argno != argc; argno++)
+ {
+ std::string option = argv[argno];
+ char const *prefix = nullptr;
+ auto ident = option.find_last_of ('?');
+ if (ident != option.npos)
+ {
+ prefix = option.c_str () + ident + 1;
+ option[ident] = 0;
+ }
+ int fd = open (option.c_str (), O_RDONLY | O_CLOEXEC);
+ int err = 0;
+ if (fd < 0)
+ err = errno;
+ else
+ {
+ err = r.read_tuple_file (fd, prefix, false);
+ close (fd);
+ }
+
+ if (err)
+ error ("failed reading '%s': %s", option.c_str (), xstrerror (err));
+ }
+ else
+ flag_fallback = true;
+ r.set_default (flag_fallback);
+
+#ifdef HAVE_AF_INET6
+ netmask_set_t::iterator end = netmask_set.end ();
+ for (netmask_set_t::iterator iter = netmask_set.begin ();
+ iter != end; ++iter)
+ {
+ netmask_vec_t::iterator e = accept_addrs.end ();
+ for (netmask_vec_t::iterator i = accept_addrs.begin (); i != e; ++i)
+ if (i->includes (iter->addr))
+ goto present;
+ accept_addrs.push_back (*iter);
+ present:;
+ }
+#endif
+
+#ifdef NETWORKING
+ if (sock_fd >= 0)
+ {
+ server (name[0] != '=', sock_fd, &r);
+ if (name[0] == '=')
+ unlink (name.c_str () + 1);
+ }
+ else
+#endif
+ {
+ gcc_assert (sock_fd < 0);
+ auto server = Cody::Server (&r, 0, 1);
+
+ int err = 0;
+ for (;;)
+ {
+ server.PrepareToRead ();
+ while ((err = server.Read ()))
+ {
+ if (err == EINTR || err == EAGAIN)
+ continue;
+ goto done;
+ }
+
+ server.ProcessRequests ();
+
+ server.PrepareToWrite ();
+ while ((err = server.Write ()))
+ {
+ if (err == EINTR || err == EAGAIN)
+ continue;
+ goto done;
+ }
+ }
+ done:;
+ if (err > 0)
+ error ("communication error:%s", xstrerror (err));
+ }
+
+ return 0;
+}
--- /dev/null
+/* C++ modules. Experimental! -*- c++ -*-
+ Copyright (C) 2017-2020 Free Software Foundation, Inc.
+ Written by Nathan Sidwell <nathan@acm.org> while at FaceBook
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+// Mapper interface for client and server bits
+#include "cody.hh"
+// C++
+#include <string>
+#include <map>
+
+// This is a GCC class, so GCC coding conventions on new bits.
+class module_resolver : public Cody::Resolver
+{
+public:
+ using parent = Cody::Resolver;
+ using module_map = std::map<std::string, std::string>;
+
+private:
+ std::string repo;
+ std::string ident;
+ module_map map;
+ int fd_repo = -1;
+ bool provide_default = true;
+
+public:
+ module_resolver (bool def = true);
+ virtual ~module_resolver () override;
+
+public:
+ void set_default (bool d)
+ {
+ provide_default = d;
+ }
+ void set_ident (char const *i)
+ {
+ ident = i;
+ }
+ bool set_repo (std::string &&repo, bool force = false);
+ bool add_mapping (std::string &&module, std::string &&file,
+ bool force = false);
+
+ // Return +ve line number of error, or -ve errno
+ int read_tuple_file (int fd, char const *prefix, bool force = false);
+ int read_tuple_file (int fd, std::string const &prefix,
+ bool force = false)
+ {
+ return read_tuple_file (fd, prefix.empty () ? nullptr : prefix.c_str (),
+ force);
+ }
+
+public:
+ // Virtual overriders, names are controlle by Cody::Resolver
+ virtual module_resolver *ConnectRequest (Cody::Server *, unsigned version,
+ std::string &agent,
+ std::string &ident)
+ override;
+ virtual int ModuleRepoRequest (Cody::Server *) override;
+ virtual int ModuleExportRequest (Cody::Server *s, std::string &module)
+ override;
+ virtual int ModuleImportRequest (Cody::Server *s, std::string &module)
+ override;
+ virtual int IncludeTranslateRequest (Cody::Server *s, std::string &include)
+ override;
+
+ virtual int LTOCompileRequest (Cody::Server *s, std::vector<std::string> &args)
+ override;
+
+private:
+ virtual char const *GetCMISuffix () override;
+
+private:
+ int cmi_response (Cody::Server *s, std::string &module);
+};
+
+#ifdef MAPPER_FOR_GCC
+#ifndef HAVE_SIGHANDLER_T
+typedef void (*sighandler_t) (int);
+#endif
+
+class module_client : public Cody::Client
+{
+ pex_obj *pex = nullptr;
+ sighandler_t sigpipe = SIG_IGN;
+
+public:
+ module_client (Cody::Server *s)
+ : Client (s)
+ {
+ }
+ module_client (pex_obj *pex, int fd_from, int fd_to);
+
+ module_client (int fd_from, int fd_to)
+ : Client (fd_from, fd_to)
+ {
+ }
+
+public:
+ static module_client *open_module_client (location_t loc, const char *option,
+ void (*set_repo) (const char *),
+ char const *);
+ static void close_module_client (location_t loc, module_client *);
+};
+
+#endif