mirror of
https://gcc.gnu.org/git/gcc.git
synced 2026-02-22 03:46:53 -05:00
Compare commits
7 Commits
devel/sphi
...
devel/lto-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d02e931dca | ||
|
|
9eebf96f87 | ||
|
|
c184dfeffa | ||
|
|
a3385aceea | ||
|
|
c647b271e8 | ||
|
|
5946cce94d | ||
|
|
0a1ce58cbd |
@@ -226,6 +226,8 @@ HOST_EXPORTS = \
|
||||
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; \
|
||||
@@ -329,6 +331,10 @@ HOST_GMPINC = @gmpinc@
|
||||
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@
|
||||
|
||||
@@ -229,6 +229,8 @@ HOST_EXPORTS = \
|
||||
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; \
|
||||
@@ -332,6 +334,10 @@ HOST_GMPINC = @gmpinc@
|
||||
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@
|
||||
|
||||
60
configure
vendored
60
configure
vendored
@@ -688,6 +688,8 @@ poststage1_ldflags
|
||||
poststage1_libs
|
||||
stage1_ldflags
|
||||
stage1_libs
|
||||
codylibinc
|
||||
codylib
|
||||
extra_isl_gmp_configure_flags
|
||||
extra_mpc_mpfr_configure_flags
|
||||
extra_mpc_gmp_configure_flags
|
||||
@@ -755,6 +757,7 @@ infodir
|
||||
docdir
|
||||
oldincludedir
|
||||
includedir
|
||||
runstatedir
|
||||
localstatedir
|
||||
sharedstatedir
|
||||
sysconfdir
|
||||
@@ -806,6 +809,9 @@ with_gmp_dir
|
||||
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
|
||||
@@ -921,6 +927,7 @@ datadir='${datarootdir}'
|
||||
sysconfdir='${prefix}/etc'
|
||||
sharedstatedir='${prefix}/com'
|
||||
localstatedir='${prefix}/var'
|
||||
runstatedir='${localstatedir}/run'
|
||||
includedir='${prefix}/include'
|
||||
oldincludedir='/usr/include'
|
||||
docdir='${datarootdir}/doc/${PACKAGE}'
|
||||
@@ -1173,6 +1180,15 @@ do
|
||||
| -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=* \
|
||||
@@ -1310,7 +1326,7 @@ fi
|
||||
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.
|
||||
@@ -1470,6 +1486,7 @@ Fine tuning of the installation directories:
|
||||
--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]
|
||||
@@ -1580,6 +1597,14 @@ Optional Packages:
|
||||
--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
|
||||
@@ -6938,6 +6963,39 @@ fi
|
||||
|
||||
|
||||
|
||||
# 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.
|
||||
|
||||
26
configure.ac
26
configure.ac
@@ -1708,6 +1708,32 @@ AC_SUBST(extra_mpc_gmp_configure_flags)
|
||||
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])],
|
||||
|
||||
@@ -388,6 +388,10 @@ GMPINC = @GMPINC@
|
||||
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@
|
||||
|
||||
@@ -1068,7 +1072,7 @@ BUILD_LIBDEPS= $(BUILD_LIBIBERTY)
|
||||
# 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@
|
||||
@@ -1102,7 +1106,7 @@ BUILD_ERRORS = build/errors.o
|
||||
# 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 $@
|
||||
@@ -1686,7 +1690,7 @@ ALL_HOST_BACKEND_OBJS = $(GCC_OBJS) $(OBJS) $(OBJS-libcommon) \
|
||||
$(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
|
||||
@@ -1761,16 +1765,22 @@ SELFTEST_DEPS = $(GCC_PASSES) stmp-int-hdrs $(srcdir)/testsuite/selftests
|
||||
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
|
||||
@@ -2185,12 +2195,28 @@ collect2$(exeext): $(COLLECT2_OBJS) $(LIBDEPS)
|
||||
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@
|
||||
@@ -3678,6 +3704,10 @@ install-common: native lang.install-common installdirs
|
||||
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.
|
||||
|
||||
@@ -302,6 +302,24 @@
|
||||
#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
|
||||
@@ -1155,6 +1173,18 @@
|
||||
#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
|
||||
@@ -1425,6 +1455,12 @@
|
||||
#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
|
||||
@@ -1689,6 +1725,12 @@
|
||||
#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
|
||||
@@ -1732,6 +1774,18 @@
|
||||
#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
|
||||
@@ -1744,6 +1798,12 @@
|
||||
#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
|
||||
@@ -1756,6 +1816,12 @@
|
||||
#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
|
||||
|
||||
306
gcc/configure
vendored
306
gcc/configure
vendored
@@ -639,6 +639,8 @@ PICFLAG
|
||||
enable_host_shared
|
||||
enable_plugin
|
||||
pluginlibs
|
||||
CODYLIBINC
|
||||
CODYLIB
|
||||
ISLINC
|
||||
ISLLIBS
|
||||
GMPINC
|
||||
@@ -1038,7 +1040,9 @@ CPP
|
||||
GMPLIBS
|
||||
GMPINC
|
||||
ISLLIBS
|
||||
ISLINC'
|
||||
ISLINC
|
||||
CODYLIB
|
||||
CODYLIBINC'
|
||||
|
||||
|
||||
# Initialize some variables set by options.
|
||||
@@ -1866,6 +1870,8 @@ Some influential environment variables:
|
||||
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.
|
||||
@@ -10192,6 +10198,14 @@ _ACEOF
|
||||
|
||||
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"
|
||||
@@ -11915,6 +11929,296 @@ $as_echo "#define HOST_HAS_F_SETLKW 1" >>confdefs.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"
|
||||
|
||||
137
gcc/configure.ac
137
gcc/configure.ac
@@ -1430,6 +1430,10 @@ fi
|
||||
|
||||
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
|
||||
|
||||
@@ -1575,6 +1579,136 @@ if test $ac_cv_f_setlkw = yes; then
|
||||
[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"
|
||||
@@ -6683,6 +6817,9 @@ if test "x${ISLLIBS}" != "x" ; then
|
||||
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)
|
||||
|
||||
@@ -46,7 +46,7 @@ CP_PLUGIN_HEADERS := cp-tree.h cxx-pretty-print.h name-lookup.h type-utils.h ope
|
||||
# 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++
|
||||
|
||||
@@ -48,6 +48,11 @@ along with GCC; see the file COPYING3. If not see
|
||||
#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. */
|
||||
@@ -84,6 +89,45 @@ static bool xassembler_options_error = false;
|
||||
|
||||
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
|
||||
@@ -1874,6 +1918,9 @@ cont:
|
||||
qsort (ltrans_priorities, nr, sizeof (int) * 2, cmp_priority);
|
||||
}
|
||||
|
||||
auto *mapper = get_mapper (main_source_loc);
|
||||
mapper->Cork();
|
||||
|
||||
/* Execute the LTRANS stage for each input file (or prepare a
|
||||
makefile to invoke this in parallel). */
|
||||
for (i = 0; i < nr; ++i)
|
||||
@@ -1917,13 +1964,42 @@ cont:
|
||||
}
|
||||
else
|
||||
{
|
||||
fork_execute (new_argv[0], CONST_CAST (char **, new_argv),
|
||||
true);
|
||||
maybe_unlink (input_name);
|
||||
// TODO: better way to figure out the number of arguments?
|
||||
for (j = 1; new_argv[j] != NULL; ++j);
|
||||
fprintf(stderr, "argc: %d\n", j);
|
||||
|
||||
mapper->InvokeSubProcess(new_argv, j);
|
||||
|
||||
// TODO: unlink input file somewhere
|
||||
// maybe_unlink (input_name);
|
||||
}
|
||||
|
||||
output_names[i] = output_name;
|
||||
}
|
||||
|
||||
auto response = mapper->Uncork();
|
||||
auto r_iter = response.begin ();
|
||||
|
||||
while(r_iter != response.end()) {
|
||||
Cody::Packet const &p = *r_iter;
|
||||
|
||||
if(p.GetCode() == Cody::Client::PC_OK) {
|
||||
fprintf(stderr, "\tlto compilation succeeded\n");
|
||||
}
|
||||
else {
|
||||
if(!p.GetString().empty()) {
|
||||
fprintf(stderr, "\tlto compilation failure message: %s\n", p.GetString().c_str());
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "\tlto compilation unknown failure\n");
|
||||
}
|
||||
}
|
||||
|
||||
++r_iter;
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
if (parallel)
|
||||
{
|
||||
struct pex_obj *pex;
|
||||
|
||||
302
gcc/mapper-client.cc
Normal file
302
gcc/mapper-client.cc
Normal file
@@ -0,0 +1,302 @@
|
||||
/* 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;
|
||||
}
|
||||
271
gcc/mapper-resolver.cc
Normal file
271
gcc/mapper-resolver.cc
Normal file
@@ -0,0 +1,271 @@
|
||||
/* 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->PathnameResponse (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->PathnameResponse (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->BoolResponse (false);
|
||||
else
|
||||
s->PathnameResponse (iter->second);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int module_resolver::InvokeSubProcessRequest (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 "INVOKE"
|
||||
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->OKResponse();
|
||||
return 0;
|
||||
}
|
||||
|
||||
990
gcc/mapper-server.cc
Normal file
990
gcc/mapper-server.cc
Normal file
@@ -0,0 +1,990 @@
|
||||
/* 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;
|
||||
}
|
||||
120
gcc/mapper.h
Normal file
120
gcc/mapper.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/* 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 InvokeSubProcessRequest (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
|
||||
Reference in New Issue
Block a user