On Fri, Jun 20, 2014 at 1:10 PM, Ian Stakenvicius <a...@gentoo.org> wrote: > Thoughts [about wrapping gcc, so that non-native multilib-build ABI's can finally return to a world where [[ ${GCC} != *' '* ]] ]?
TLDR: good idea, I'm strongly in favor of it. A wrapper would fix horrors like the following, which, last I checked, was sort-of required* on ABI_X86="*32*" DEFAULT_ABI="amd64" systems with crossdev i686-pc-linux-gnu targets in ${PATH}: --- /usr/portage/eclass/cmake-utils.eclass 2014-05-06 08:31:17.000000000 -0700 +++ /usr/local/portage/gogogmt/eclass/cmake-utils.eclass 2014-06-01 12:36:40.753904765 -0700 @@ -373,14 +373,115 @@ enable_cmake-utils_src_prepare() { } + +# retrieve a variable (i.e.: FOO) using i.e.: tc_getFOO, +# unless the variable is already defined to a nonempty value, +# in which case, it is returned unaltered +_cmake-utils_tc_get_if_needed() { + local v="$1" s + if [[ ${!v} ]] ; then + s="${!v}" + else + s=$(tc-get${v}) + fi + echo "${s}" +} + + +# trim the preceeding and trailing whitespace from a string, +# leaving inner spaces intact +_cmake-utils_trimmed() { + local s="$*" + while [[ ${s:0:1} =~ [[:space:]] ]] ; do + s="${s:1}" + done + while [[ ${s:$((${#s}-1))} =~ [[:space:]] ]] ; do + s="${s:0:$((${#s}-1))}" + done + echo "${s}" +} + +# given a string, retrieve the first word (consisting of non-space characters) +# after trimming any leading whitespace. +_cmake-utils_first_word_of() { + local s=$(_cmake-utils_trimmed "$*") + echo "${s%% *}" +} + +# given a string, retrieve the rest of the string after the first word, +# with any whitespace trimmed, retaining any whitespace between words +# (except whitespace that was between the first and second word) +_cmake-utils_subsequent_words_of() { + local s=$(_cmake-utils_trimmed "$*") + if [[ ${s} ]] ; then + s="${s#$(_cmake-utils_first_word_of "${s}")}" + echo "$(_cmake-utils_trimmed "${s}")" + else + echo "" + fi +} + +# given a variable-name, retrieve it with _cmake-utils_tc_get_if_needed +# and then from that retreive the first word +_cmake-utils_get_first_word() { + local s=$(_cmake-utils_tc_get_if_needed "$1") + echo "$(_cmake-utils_first_word_of "${s}")" +} + +# given a command-containing variable as the first argument, +# uses _cmake-utils_tc_get_if_needed to retrieve the var, and then +# returns type -P of the first word of it, ignoring rest. +_cmake-utils_get_first_word_executable() { + local w=$(_cmake-utils_get_first_word "$1") + if [[ ${w} ]] ; then + echo "$(type -P "${w}")" + else + echo "" + fi +} + +# fetches any additional bits of a variable not included in +# _cmake-utils_get_first_word. takes the variable name as an input. +# May return an empty string. +_cmake-utils_get_subsequent_words() { + local s=$(_cmake-utils_tc_get_if_needed "$1") + echo "$(_cmake-utils_subsequent_words_of "${s}")" } # @VARIABLE: mycmakeargs @@ -433,17 +534,46 @@ enable_cmake-utils_src_configure() { # Prepare Gentoo override rules (set valid compiler, append CPPFLAGS etc.) local build_rules=${BUILD_DIR}/gentoo_rules.cmake + + local _CMAKE_C_COMPILER=$(_cmake-utils_get_first_word_executable CC) + local _CCORPHANS=$(_cmake-utils_get_subsequent_words CC) + local _CMAKE_C_COMPILER_ARG1_COMMAND= + local _CMAKE_CXX_COMPILER=$(_cmake-utils_get_first_word_executable CXX) + local _CXXORPHANS=$(_cmake-utils_get_subsequent_words CXX) + local _CMAKE_CXX_COMPILER_ARG1_COMMAND= + + # This seems fairly rediculous to me, but if C{,XX}ORPHANS is nonempty, then, in order to prevent + # duplication of the first argument, we must handle the first word specially + if [[ ${_CCORPHANS} ]] ; then + _CMAKE_C_COMPILER_ARG1_COMMAND="SET (CMAKE_C_COMPILER_ARG1 $(_cmake-utils_first_word_of "${_CCORPHANS}") CACHE STRING \"C compiler first argument\" FORCE)" + _CCORPHANS=$(_cmake-utils_subsequent_words_of "${_CCORPHANS}") + fi + if [[ ${_CXXORPHANS} ]] ; then + _CMAKE_CXX_COMPILER_ARG1_COMMAND="SET (CMAKE_CXX_COMPILER_ARG1 $(_cmake-utils_first_word_of "${_CXXORPHANS}") CACHE STRING \"C++ compiler first argument\" FORCE)" + _CXXORPHANS=$(_cmake-utils_subsequent_words_of "${_CXXORPHANS}") + fi + cat > "${build_rules}" <<- _EOF_ - SET (CMAKE_AR $(type -P $(tc-getAR)) CACHE FILEPATH "Archive manager" FORCE) - SET (CMAKE_ASM_COMPILE_OBJECT "<CMAKE_C_COMPILER> <DEFINES> ${CFLAGS} <FLAGS> -o <OBJECT> -c <SOURCE>" CACHE STRING "ASM compile command" FORCE) - SET (CMAKE_C_COMPILER $(type -P $(tc-getCC)) CACHE FILEPATH "C compiler" FORCE) - SET (CMAKE_C_COMPILE_OBJECT "<CMAKE_C_COMPILER> <DEFINES> ${CPPFLAGS} <FLAGS> -o <OBJECT> -c <SOURCE>" CACHE STRING "C compile command" FORCE) - SET (CMAKE_CXX_COMPILER $(type -P $(tc-getCXX)) CACHE FILEPATH "C++ compiler" FORCE) - SET (CMAKE_CXX_COMPILE_OBJECT "<CMAKE_CXX_COMPILER> <DEFINES> ${CPPFLAGS} <FLAGS> -o <OBJECT> -c <SOURCE>" CACHE STRING "C++ compile command" FORCE) - SET (CMAKE_RANLIB $(type -P $(tc-getRANLIB)) CACHE FILEPATH "Archive index generator" FORCE) - SET (PKG_CONFIG_EXECUTABLE $(type -P $(tc-getPKG_CONFIG)) CACHE FILEPATH "pkg-config executable" FORCE) + SET (CMAKE_C_COMPILER "${_CMAKE_C_COMPILER}" CACHE FILEPATH "C compiler" FORCE) + ${_CMAKE_C_COMPILER_ARG1_COMMAND} + SET (CMAKE_CXX_COMPILER "${_CMAKE_CXX_COMPILER}" CACHE FILEPATH "C++ compiler" FORCE) + ${_CMAKE_CXX_COMPILER_ARG1_COMMAND} + SET (CMAKE_AR "$(_cmake-utils_get_first_word_executable AR)" CACHE FILEPATH "Archive manager" FORCE) + SET (CMAKE_RANLIB "$(_cmake-utils_get_first_word_executable RANLIB)" CACHE FILEPATH "Archive index generator" FORCE) + SET (CMAKE_ASM_COMPILE_OBJECT "<CMAKE_C_COMPILER> ${_CCORPHANS}${_CCORPHANS:+ }<DEFINES> ${CFLAGS}${CFLAGS:+ }<FLAGS> -o <OBJECT> -c <SOURCE>" CACHE STRING "ASM compile command" FORCE) + SET (CMAKE_C_COMPILE_OBJECT "<CMAKE_C_COMPILER> ${_CCORPHANS}${_CCORPHANS:+ }<DEFINES> ${CFLAGS}${CFLAGS:+ }<FLAGS> -o <OBJECT> -c <SOURCE>" CACHE STRING "C compile command" FORCE) + SET (CMAKE_CXX_COMPILE_OBJECT "<CMAKE_CXX_COMPILER> ${_CXXORPHANS}${_CXXORPHANS:+ }<DEFINES> ${CXXFLAGS}${CXXFLAGS:+ }<FLAGS> -o <OBJECT> -c <SOURCE>" CACHE STRING "C++ compile command" FORCE) + SET (CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> ${_CCORPHANS}${_CCORPHANS:+ }<FLAGS> ${LDFLAGS}${LDFLAGS:+ }<CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>" CACHE STRING "C link command for executables" FORCE) + SET (CMAKE_C_CREATE_SHARED_LIBRARY "<CMAKE_C_COMPILER> ${_CCORPHANS}${_CCORPHANS:+ }<CMAKE_SHARED_LIBRARY_C_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${LDFLAGS}${LDFLAGS:+ }<CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_C_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>" CACHE STRING "C shared library link command" FORCE) + SET (CMAKE_C_CREATE_SHARED_MODULE "\${CMAKE_C_CREATE_SHARED_LIBRARY}" CACHE STRING "C shared module link command" FORCE) + SET (CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> ${_CXXORPHANS}${_CXXORPHANS:+ }<FLAGS> ${LDFLAGS}${LDFLAGS:+ }<CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>" CACHE STRING "C++ link command for executables" FORCE) + SET (CMAKE_CXX_CREATE_SHARED_LIBRARY "<CMAKE_CXX_COMPILER> ${_CXXORPHANS}${_CXXORPHANS:+ }<CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${LDFLAGS}${LDFLAGS:+ }<CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>" CACHE STRING "C++ shared library link command" FORCE) + SET (CMAKE_CXX_CREATE_SHARED_MODULE "\${CMAKE_CXX_CREATE_SHARED_LIBRARY}" CACHE STRING "C++ shared module link command" FORCE) + SET (PKG_CONFIG_EXECUTABLE "$(_cmake-utils_get_first_word_executable PKG_CONFIG)" CACHE FILEPATH "pkg-config executable" FORCE) _EOF_ has "${EAPI:-0}" 0 1 2 && ! use prefix && EPREFIX= Perhaps a straw-man argument, since, the above code could be made more beautiful, and then it would not be so ugly :P But, it's not just that cmake can't properly handle a C{C,XX} variables with spaces in them**. There are a bunch of similar places where we had to patch Makefiles and autotools to wedge GCC="foo bar" support in. Without hyperbole, I can honestly say, it's a lame and inelegant hack to put an /argument/ into GCC. -m${foo} is a CFLAG, not a compiler. "Everyone" knows GCC is a variable that names an executable -- but in multilib-build, for some god-awful reason, we've made it into some other thing, a hybrid-psuedo-thing that really only makes sense in a shell script, and even then, only in an improperly coded shell script :). Even if that rubicon was already crossed by ccache, distcc, etc, there is a reason none of them /require/ it. It's just asking for trouble. We'll just keep wasting time fixing subtle bugs like the above, because of it until we break down and fix it. I'd lay pretty long odds that five years from now we are still clinging to it, should we decide to stick with the status quo for now. So why not bite the bullet and save ourselves the hassle? -gmt * perhaps today the problem is mitigated, due to the same gcc-${pseudo-CHOST} executables now existing for upstream multilib-build pseudo-targets -- but, I'll bet, not solved. Usually trouble only crops up for larger framework builds with lots of sub-dirs, like qt or mysql-server, and manifests as incorrect attempts to link native libraries in -- which the compiler might or might not manage to save you from at the last moment... also note that patch is mocked up for easy reading -- it won't apply. See my overlay for the real code. Finally, sorry for the HTML -- I'm writing from the gmail ajax which obstinately refuses to allow plain-text inline patches. ** IIRC, it would be more precise to say something like "cmake's in-built hacks for the CC='exectutable argument' circumstance are subtly incompatible with our means of injecting the portage compiler values into cmake (or so things used to be; I suspect the problem still lurks to some extent), and that this ultimately manifests as confusing, intermittent build failures and correctly issued QA warnings in larger multilib-build-based ebuilds (or will in the near future; I actually wouldn't know as I run with the above patches :P), esp. in cases where a ${CC}-${CHOST} or ${CXX}-${CHOST} executables are to be found in ${PATH}." But if any unlucky person is still reading, they can see fully why I didn't bother to say all that :P