diff options
35 files changed, 1171 insertions, 345 deletions
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 38cc0d8..ec25596 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -119,6 +119,7 @@ Properties on Targets /prop_tgt/ARCHIVE_OUTPUT_DIRECTORY /prop_tgt/ARCHIVE_OUTPUT_NAME_CONFIG /prop_tgt/ARCHIVE_OUTPUT_NAME + /prop_tgt/AUTOGEN_BUILD_DIR /prop_tgt/AUTOGEN_TARGET_DEPENDS /prop_tgt/AUTOMOC_DEPEND_FILTERS /prop_tgt/AUTOMOC_MOC_OPTIONS diff --git a/Help/manual/cmake-qt.7.rst b/Help/manual/cmake-qt.7.rst index 3b95b05..9f3968c 100644 --- a/Help/manual/cmake-qt.7.rst +++ b/Help/manual/cmake-qt.7.rst @@ -68,14 +68,24 @@ be included by the user in the C++ implementation file with a preprocessor ``#include``. Included ``moc_*.cpp`` and ``*.moc`` files will be generated in the -``<CMAKE_CURRENT_BINARY_DIR>/<TARGETNAME>_autogen/include`` directory which is +``<AUTOGEN_BUILD_DIR>/include`` directory which is automatically added to the target's :prop_tgt:`INCLUDE_DIRECTORIES`. (This differs from CMake 3.7 and below; see their documentation for details.) +* For multi configuration generators, except Xcode, the include directory is + ``<AUTOGEN_BUILD_DIR>/include_<CONFIG>``. + +* See :prop_tgt:`AUTOGEN_BUILD_DIR`. + Not included ``moc_<basename>.cpp`` files will be generated in custom folders to avoid name collisions and included in a separate -``<CMAKE_CURRENT_BINARY_DIR>/<TARGETNAME>_autogen/moc_compilation.cpp`` -file which is compiled into the target. +``<AUTOGEN_BUILD_DIR>/mocs_compilation.cpp`` file which is compiled +into the target. + +* For multi configuration generators, except Xcode, the file is + ``<AUTOGEN_BUILD_DIR>/mocs_compilation_<CONFIG>.cpp``. + +* See :prop_tgt:`AUTOGEN_BUILD_DIR`. The ``moc`` command line will consume the :prop_tgt:`COMPILE_DEFINITIONS` and :prop_tgt:`INCLUDE_DIRECTORIES` target properties from the target it is being @@ -109,10 +119,15 @@ searched for first in the vicinity of including file and afterwards in the optional :prop_tgt:`AUTOUIC_SEARCH_PATHS` of the target. The generated generated ``ui_*.h`` files are placed in the -``<CMAKE_CURRENT_BINARY_DIR>/<TARGETNAME>_autogen/include`` directory which is +``<AUTOGEN_BUILD_DIR>/include`` directory which is automatically added to the target's :prop_tgt:`INCLUDE_DIRECTORIES`. (This differs from CMake 3.7 and below; see their documentation for details.) +* For multi configuration generators, except Xcode, the include directory is + ``<AUTOGEN_BUILD_DIR>/include_<CONFIG>``. + +* See :prop_tgt:`AUTOGEN_BUILD_DIR`. + The :prop_tgt:`AUTOUIC` target property may be pre-set for all following targets by setting the :variable:`CMAKE_AUTOUIC` variable. The :prop_tgt:`AUTOUIC_OPTIONS` target property may be populated to set options diff --git a/Help/prop_tgt/AUTOGEN_BUILD_DIR.rst b/Help/prop_tgt/AUTOGEN_BUILD_DIR.rst new file mode 100644 index 0000000..8db6ede --- /dev/null +++ b/Help/prop_tgt/AUTOGEN_BUILD_DIR.rst @@ -0,0 +1,17 @@ +AUTOGEN_BUILD_DIR +----------------- + +Directory where :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTOUIC` and :prop_tgt:`AUTORCC` +generate files for the target. + +The directory is created on demand and automatically added to the +:prop_dir:`ADDITIONAL_MAKE_CLEAN_FILES`. + +When unset or empty the directory ``<dir>/<target-name>_autogen`` is used where +``<dir>`` is :variable:`CMAKE_CURRENT_BINARY_DIR` and ``<target-name>`` +is :prop_tgt:`NAME`. + +By default :prop_tgt:`AUTOGEN_BUILD_DIR` is unset. + +See the :manual:`cmake-qt(7)` manual for more information on using CMake +with Qt. diff --git a/Help/prop_tgt/AUTOMOC.rst b/Help/prop_tgt/AUTOMOC.rst index 7e10fde..81eff82 100644 --- a/Help/prop_tgt/AUTOMOC.rst +++ b/Help/prop_tgt/AUTOMOC.rst @@ -13,13 +13,17 @@ source files at build time and invoke moc accordingly. * If an ``#include`` statement like ``#include "moc_<basename>.cpp"`` is found, the ``Q_OBJECT`` or ``Q_GADGET`` macros are expected in an otherwise empty - line of the ``<basename>.h(xx)`` header file. ``moc`` is run on the header file to - generate ``moc_<basename>.cpp`` in the - ``<CMAKE_CURRENT_BINARY_DIR>/<TARGETNAME>_autogen/include`` directory - which is automatically added to the target's - :prop_tgt:`INCLUDE_DIRECTORIES`. This allows the compiler to find the - included ``moc_<basename>.cpp`` file regardless of the location the - original source. + line of the ``<basename>.h(xx)`` header file. ``moc`` is run on the header + file to generate ``moc_<basename>.cpp`` in the + ``<AUTOGEN_BUILD_DIR>/include`` directory which is automatically added + to the target's :prop_tgt:`INCLUDE_DIRECTORIES`. + This allows the compiler to find the included ``moc_<basename>.cpp`` file + regardless of the location the original source. + + * For multi configuration generators, except Xcode, the include directory is + ``<AUTOGEN_BUILD_DIR>/include_<CONFIG>``. + + * See :prop_tgt:`AUTOGEN_BUILD_DIR`. * If an ``#include`` statement like ``#include "<basename>.moc"`` is found, then ``Q_OBJECT`` or ``Q_GADGET`` macros are expected in the current source @@ -28,10 +32,19 @@ source files at build time and invoke moc accordingly. * Header files that are not included by an ``#include "moc_<basename>.cpp"`` statement are nonetheless scanned for ``Q_OBJECT`` or ``Q_GADGET`` macros. The resulting ``moc_<basename>.cpp`` files are generated in custom - directories and automatically included in the generated - ``<CMAKE_CURRENT_BINARY_DIR>/<TARGETNAME>_autogen/moc_compilation.cpp`` file, - which is compiled as part of the target. The custom directories help to - avoid name collisions for moc files with the same ``<basename>``. + directories and automatically included in a generated + ``<AUTOGEN_BUILD_DIR>/mocs_compilation.cpp`` file, + which is compiled as part of the target. + + * For multi configuration generators, except Xcode, the file names are + ``moc_<basename>_<CONFIG>.cpp`` and + ``<AUTOGEN_BUILD_DIR>/mocs_compilation_<CONFIG>.cpp``. + + * The custom directories with checksum + based names help to avoid name collisions for moc files with the same + ``<basename>``. + + * See :prop_tgt:`AUTOGEN_BUILD_DIR`. * Additionally, header files with the same base name as a source file, (like ``<basename>.h``) or ``_p`` appended to the base name (like diff --git a/Help/prop_tgt/AUTOUIC.rst b/Help/prop_tgt/AUTOUIC.rst index 91d95e5..4a08072 100644 --- a/Help/prop_tgt/AUTOUIC.rst +++ b/Help/prop_tgt/AUTOUIC.rst @@ -14,8 +14,13 @@ and invoke ``uic`` accordingly. If an ``#include`` statement like searched for first in the vicinity of ``source.cpp`` and afterwards in the optional :prop_tgt:`AUTOUIC_SEARCH_PATHS` of the target. ``uic`` is run on the ``foo.ui`` file to generate ``ui_foo.h`` in the directory -``<CMAKE_CURRENT_BINARY_DIR>/<TARGETNAME>_autogen/include``, -which is added to the target's :prop_tgt:`INCLUDE_DIRECTORIES` automatically. +``<AUTOGEN_BUILD_DIR>/include``, +which is automatically added to the target's :prop_tgt:`INCLUDE_DIRECTORIES`. + +* For multi configuration generators, except Xcode, the include directory is + ``<AUTOGEN_BUILD_DIR>/include_<CONFIG>``. + +* See :prop_tgt:`AUTOGEN_BUILD_DIR`. This property is initialized by the value of the :variable:`CMAKE_AUTOUIC` variable if it is set when a target is created. diff --git a/Help/release/dev/Autogen_build_dir.rst b/Help/release/dev/Autogen_build_dir.rst new file mode 100644 index 0000000..d11c00b --- /dev/null +++ b/Help/release/dev/Autogen_build_dir.rst @@ -0,0 +1,6 @@ +AutoGen build dir +----------------- + +* The new target property :prop_tgt:`AUTOGEN_BUILD_DIR` was introduced which + allows to set a custom output directory for + :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTOUIC` and :prop_tgt:`AUTORCC`. diff --git a/Help/release/dev/FindProtobuf-export-macro.rst b/Help/release/dev/FindProtobuf-export-macro.rst new file mode 100644 index 0000000..43d9223 --- /dev/null +++ b/Help/release/dev/FindProtobuf-export-macro.rst @@ -0,0 +1,6 @@ +FindProtobuf-export-macro +------------------------- + +* The :module:`FindProtobuf` module :command:`protobuf_generate_cpp` + command gained an ``EXPORT_MACRO`` option to specify the name of + a DLL export markup macro. diff --git a/Modules/AutogenInfo.cmake.in b/Modules/AutogenInfo.cmake.in index 5e945bc..4e85474 100644 --- a/Modules/AutogenInfo.cmake.in +++ b/Modules/AutogenInfo.cmake.in @@ -1,12 +1,10 @@ -# Target names -set(AM_TARGET_NAME @_autogen_target_name@) -set(AM_ORIGIN_TARGET_NAME @_origin_target_name@) # Directories and files set(AM_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@/") set(AM_CMAKE_SOURCE_DIR "@CMAKE_SOURCE_DIR@/") set(AM_CMAKE_CURRENT_SOURCE_DIR "@CMAKE_CURRENT_SOURCE_DIR@/") set(AM_CMAKE_CURRENT_BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@/") set(AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE "@CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE@") +set(AM_BUILD_DIR @_autogen_build_dir@) set(AM_SOURCES @_sources@) set(AM_HEADERS @_headers@) # Qt environment diff --git a/Modules/FindProtobuf.cmake b/Modules/FindProtobuf.cmake index abc7518..33262f3 100644 --- a/Modules/FindProtobuf.cmake +++ b/Modules/FindProtobuf.cmake @@ -76,6 +76,7 @@ # include_directories(${Protobuf_INCLUDE_DIRS}) # include_directories(${CMAKE_CURRENT_BINARY_DIR}) # protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS foo.proto) +# protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS EXPORT_MACRO DLL_EXPORT foo.proto) # protobuf_generate_python(PROTO_PY foo.proto) # add_executable(bar bar.cc ${PROTO_SRCS} ${PROTO_HDRS}) # target_link_libraries(bar ${Protobuf_LIBRARIES}) @@ -89,12 +90,15 @@ # # Add custom commands to process ``.proto`` files to C++:: # -# protobuf_generate_cpp (<SRCS> <HDRS> [<ARGN>...]) +# protobuf_generate_cpp (<SRCS> <HDRS> [EXPORT_MACRO <MACRO>] [<ARGN>...]) # # ``SRCS`` # Variable to define with autogenerated source files # ``HDRS`` # Variable to define with autogenerated header files +# ``EXPORT_MACRO`` +# is a macro which should expand to ``__declspec(dllexport)`` or +# ``__declspec(dllimport)`` depending on what is being compiled. # ``ARGN`` # ``.proto`` files # @@ -110,14 +114,21 @@ # ``.proto`` filess function(PROTOBUF_GENERATE_CPP SRCS HDRS) - if(NOT ARGN) + cmake_parse_arguments(protobuf "" "EXPORT_MACRO" "" ${ARGN}) + + set(PROTO_FILES "${protobuf_UNPARSED_ARGUMENTS}") + if(NOT PROTO_FILES) message(SEND_ERROR "Error: PROTOBUF_GENERATE_CPP() called without any proto files") return() endif() + if(protobuf_EXPORT_MACRO) + set(DLL_EXPORT_DECL "dllexport_decl=${protobuf_EXPORT_MACRO}:") + endif() + if(PROTOBUF_GENERATE_CPP_APPEND_PATH) # Create an include path for each file specified - foreach(FIL ${ARGN}) + foreach(FIL ${PROTO_FILES}) get_filename_component(ABS_FIL ${FIL} ABSOLUTE) get_filename_component(ABS_PATH ${ABS_FIL} PATH) list(FIND _protobuf_include_path ${ABS_PATH} _contains_already) @@ -145,7 +156,7 @@ function(PROTOBUF_GENERATE_CPP SRCS HDRS) set(${SRCS}) set(${HDRS}) - foreach(FIL ${ARGN}) + foreach(FIL ${PROTO_FILES}) get_filename_component(ABS_FIL ${FIL} ABSOLUTE) get_filename_component(FIL_WE ${FIL} NAME_WE) if(NOT PROTOBUF_GENERATE_CPP_APPEND_PATH) @@ -162,7 +173,7 @@ function(PROTOBUF_GENERATE_CPP SRCS HDRS) OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc" "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h" COMMAND ${Protobuf_PROTOC_EXECUTABLE} - ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR} ${_protobuf_include_path} ${ABS_FIL} + ARGS "--cpp_out=${DLL_EXPORT_DECL}${CMAKE_CURRENT_BINARY_DIR}" ${_protobuf_include_path} ${ABS_FIL} DEPENDS ${ABS_FIL} ${Protobuf_PROTOC_EXECUTABLE} COMMENT "Running C++ protocol buffer compiler on ${FIL}" VERBATIM ) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 721de39..42be644 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 8) -set(CMake_VERSION_PATCH 20170526) +set(CMake_VERSION_PATCH 20170528) #set(CMake_VERSION_RC 1) diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index 239b18d..6b85c66 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -7,6 +7,7 @@ #include "cmCustomCommandLines.h" #include "cmFilePathChecksum.h" #include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmOutputConverter.h" @@ -67,17 +68,19 @@ static std::string GetAutogenTargetFilesDir(cmGeneratorTarget const* target) targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory(); targetDir += "/"; targetDir += GetAutogenTargetName(target); - targetDir += ".dir/"; + targetDir += ".dir"; return targetDir; } static std::string GetAutogenTargetBuildDir(cmGeneratorTarget const* target) { - cmMakefile* makefile = target->Target->GetMakefile(); - std::string targetDir = makefile->GetCurrentBinaryDirectory(); - targetDir += "/"; - targetDir += GetAutogenTargetName(target); - targetDir += "/"; + std::string targetDir = GetSafeProperty(target, "AUTOGEN_BUILD_DIR"); + if (targetDir.empty()) { + cmMakefile* makefile = target->Target->GetMakefile(); + targetDir = makefile->GetCurrentBinaryDirectory(); + targetDir += "/"; + targetDir += GetAutogenTargetName(target); + } return targetDir; } @@ -151,6 +154,50 @@ static void GetCompileDefinitionsAndDirectories( } } +static bool IsMultiConfig(cmGlobalGenerator* globalGen) +{ + // FIXME: Xcode does not support per-config sources, yet. + // (EXCLUDED_SOURCE_FILE_NAMES) + // Treat it as a single configuration generator meanwhile. + if (globalGen->GetName().find("Xcode") != std::string::npos) { + return false; + } + return globalGen->IsMultiConfig(); +} + +static std::vector<std::string> GetConfigurations( + cmMakefile* makefile, std::string* config = CM_NULLPTR) +{ + std::vector<std::string> configs; + { + std::string cfg = makefile->GetConfigurations(configs); + if (config != CM_NULLPTR) { + *config = cfg; + } + } + // Add empty configuration on demand + if (configs.empty()) { + configs.push_back(""); + } + return configs; +} + +static std::vector<std::string> GetConfigurationSuffixes(cmMakefile* makefile) +{ + std::vector<std::string> suffixes; + if (IsMultiConfig(makefile->GetGlobalGenerator())) { + makefile->GetConfigurations(suffixes); + for (std::vector<std::string>::iterator it = suffixes.begin(); + it != suffixes.end(); ++it) { + it->insert(0, "_"); + } + } + if (suffixes.empty()) { + suffixes.push_back(""); + } + return suffixes; +} + static void AddDefinitionEscaped(cmMakefile* makefile, const char* key, const std::string& value) { @@ -220,6 +267,17 @@ static bool AddToSourceGroup(cmMakefile* makefile, const std::string& fileName, return true; } +static void AddGeneratedSource(cmMakefile* makefile, + const std::string& filename, + cmQtAutoGeneratorCommon::GeneratorType genType) +{ + cmSourceFile* gFile = makefile->GetOrCreateSource(filename, true); + gFile->SetProperty("GENERATED", "1"); + gFile->SetProperty("SKIP_AUTOGEN", "On"); + + AddToSourceGroup(makefile, filename, genType); +} + static void AcquireScanFiles(cmGeneratorTarget const* target, std::vector<std::string>& mocUicSources, std::vector<std::string>& mocUicHeaders, @@ -276,10 +334,11 @@ static void AcquireScanFiles(cmGeneratorTarget const* target, static void MocSetupAutoTarget( cmGeneratorTarget const* target, const std::string& autogenTargetName, - const std::string& qtMajorVersion, + std::string const& qtMajorVersion, std::string const& config, + std::vector<std::string> const& configs, std::vector<std::string> const& mocSkipList, - std::map<std::string, std::string>& configIncludes, - std::map<std::string, std::string>& configDefines) + std::map<std::string, std::string>& configMocIncludes, + std::map<std::string, std::string>& configMocDefines) { cmLocalGenerator* lg = target->GetLocalGenerator(); cmMakefile* makefile = target->Target->GetMakefile(); @@ -301,35 +360,26 @@ static void MocSetupAutoTarget( } // Moc includes and compile definitions { - std::string _moc_incs; - std::string _moc_compile_defs; - std::vector<std::string> configs; - { - const std::string& config = makefile->GetConfigurations(configs); - GetCompileDefinitionsAndDirectories(target, config, _moc_incs, - _moc_compile_defs); - AddDefinitionEscaped(makefile, "_moc_incs", _moc_incs); - AddDefinitionEscaped(makefile, "_moc_compile_defs", _moc_compile_defs); - } + // Default settings + std::string incs; + std::string compileDefs; + GetCompileDefinitionsAndDirectories(target, config, incs, compileDefs); + AddDefinitionEscaped(makefile, "_moc_incs", incs); + AddDefinitionEscaped(makefile, "_moc_compile_defs", compileDefs); + + // Configuration specific settings for (std::vector<std::string>::const_iterator li = configs.begin(); li != configs.end(); ++li) { - std::string config_moc_incs; - std::string config_moc_compile_defs; - GetCompileDefinitionsAndDirectories(target, *li, config_moc_incs, - config_moc_compile_defs); - if (config_moc_incs != _moc_incs) { - configIncludes[*li] = - cmOutputConverter::EscapeForCMake(config_moc_incs); - if (_moc_incs.empty()) { - _moc_incs = config_moc_incs; - } + std::string configIncs; + std::string configCompileDefs; + GetCompileDefinitionsAndDirectories(target, *li, configIncs, + configCompileDefs); + if (configIncs != incs) { + configMocIncludes[*li] = cmOutputConverter::EscapeForCMake(configIncs); } - if (config_moc_compile_defs != _moc_compile_defs) { - configDefines[*li] = - cmOutputConverter::EscapeForCMake(config_moc_compile_defs); - if (_moc_compile_defs.empty()) { - _moc_compile_defs = config_moc_compile_defs; - } + if (configCompileDefs != compileDefs) { + configMocDefines[*li] = + cmOutputConverter::EscapeForCMake(configCompileDefs); } } } @@ -375,7 +425,8 @@ static void UicGetOpts(cmGeneratorTarget const* target, } static void UicSetupAutoTarget( - cmGeneratorTarget const* target, const std::string& qtMajorVersion, + cmGeneratorTarget const* target, std::string const& qtMajorVersion, + std::string const& config, std::vector<std::string> const& configs, std::vector<std::string> const& uicSkipList, std::map<std::string, std::string>& configUicOptions) { @@ -396,25 +447,21 @@ static void UicSetupAutoTarget( } AddDefinitionEscaped(makefile, "_uic_search_paths", uicSearchPaths); } - // Uic target options { - std::string _uic_opts; - std::vector<std::string> configs; - UicGetOpts(target, makefile->GetConfigurations(configs), _uic_opts); - - AddDefinitionEscaped(makefile, "_uic_target_options", _uic_opts); + // Default settings + std::string uicOpts; + UicGetOpts(target, config, uicOpts); + AddDefinitionEscaped(makefile, "_uic_target_options", uicOpts); + // Configuration specific settings for (std::vector<std::string>::const_iterator li = configs.begin(); li != configs.end(); ++li) { - std::string config_uic_opts; - UicGetOpts(target, *li, config_uic_opts); - if (config_uic_opts != _uic_opts) { + std::string configUicOpts; + UicGetOpts(target, *li, configUicOpts); + if (configUicOpts != uicOpts) { configUicOptions[*li] = - cmOutputConverter::EscapeForCMake(config_uic_opts); - if (_uic_opts.empty()) { - _uic_opts = config_uic_opts; - } + cmOutputConverter::EscapeForCMake(configUicOpts); } } } @@ -623,14 +670,24 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenSources( { if (target->GetPropertyAsBool("AUTOMOC")) { cmMakefile* makefile = target->Target->GetMakefile(); - std::string mocCppFile = GetAutogenTargetBuildDir(target); - mocCppFile += "moc_compilation.cpp"; - { - cmSourceFile* gFile = makefile->GetOrCreateSource(mocCppFile, true); - gFile->SetProperty("SKIP_AUTOGEN", "On"); + const std::vector<std::string> suffixes = + GetConfigurationSuffixes(makefile); + // Get build directory + const std::string autogenBuildDir = GetAutogenTargetBuildDir(target); + // Register all compilation files as generated + for (std::vector<std::string>::const_iterator it = suffixes.begin(); + it != suffixes.end(); ++it) { + std::string mcFile = autogenBuildDir + "/mocs_compilation"; + mcFile += *it; + mcFile += ".cpp"; + AddGeneratedSource(makefile, mcFile, cmQtAutoGeneratorCommon::MOC); + } + // Mocs compilation file + if (IsMultiConfig(target->GetGlobalGenerator())) { + target->AddSource(autogenBuildDir + "/mocs_compilation_$<CONFIG>.cpp"); + } else { + target->AddSource(autogenBuildDir + "/mocs_compilation.cpp"); } - target->AddSource(mocCppFile); - AddToSourceGroup(makefile, mocCppFile, cmQtAutoGeneratorCommon::MOC); } } @@ -643,21 +700,30 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( const bool mocEnabled = target->GetPropertyAsBool("AUTOMOC"); const bool uicEnabled = target->GetPropertyAsBool("AUTOUIC"); const bool rccEnabled = target->GetPropertyAsBool("AUTORCC"); + const bool multiConfig = IsMultiConfig(target->GetGlobalGenerator()); const std::string autogenTargetName = GetAutogenTargetName(target); const std::string autogenBuildDir = GetAutogenTargetBuildDir(target); const std::string workingDirectory = cmSystemTools::CollapseFullPath("", makefile->GetCurrentBinaryDirectory()); const std::string qtMajorVersion = GetQtMajorVersion(target); const std::string rccCommand = RccGetExecutable(target, qtMajorVersion); + const std::vector<std::string> suffixes = GetConfigurationSuffixes(makefile); std::vector<std::string> autogenDepends; std::vector<std::string> autogenProvides; + // Remove build directories on cleanup + makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", + autogenBuildDir.c_str(), false); + // Remove old settings on cleanup { - std::string fname = GetAutogenTargetFilesDir(target); - fname += "/AutogenOldSettings.cmake"; - makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", fname.c_str(), - false); + std::string base = GetAutogenTargetFilesDir(target); + for (std::vector<std::string>::const_iterator it = suffixes.begin(); + it != suffixes.end(); ++it) { + std::string fname = base + "/AutogenOldSettings" + *it + ".cmake"; + makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", fname.c_str(), + false); + } } // Compose command lines @@ -698,22 +764,26 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( autogenComment = "Automatic " + tools + " for target " + target->GetName(); } - // Create autogen target build directory and add it to the clean files - cmSystemTools::MakeDirectory(autogenBuildDir); - makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", - autogenBuildDir.c_str(), false); + // Add moc compilation to generated files list + if (mocEnabled) { + for (std::vector<std::string>::const_iterator it = suffixes.begin(); + it != suffixes.end(); ++it) { + std::string mcFile = autogenBuildDir + "/mocs_compilation"; + mcFile += *it; + mcFile += ".cpp"; + autogenProvides.push_back(mcFile); + } + } - // Create autogen target includes directory and - // add it to the origin target INCLUDE_DIRECTORIES + // Add autogen includes directory to the origin target INCLUDE_DIRECTORIES if (mocEnabled || uicEnabled) { - const std::string incsDir = autogenBuildDir + "include"; - cmSystemTools::MakeDirectory(incsDir); - target->AddIncludeDirectory(incsDir, true); - } + if (multiConfig) { + target->AddIncludeDirectory(autogenBuildDir + "/include_$<CONFIG>", + true); - // Register moc compilation file as generated - if (mocEnabled) { - autogenProvides.push_back(autogenBuildDir + "moc_compilation.cpp"); + } else { + target->AddIncludeDirectory(autogenBuildDir + "/include", true); + } } #if defined(_WIN32) && !defined(__CYGWIN__) @@ -784,23 +854,29 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( // Compose rcc output file name { - std::string rccOut = autogenBuildDir; - rccOut += fpathCheckSum.getPart(absFile); - rccOut += "/qrc_"; - rccOut += + std::string rccOutBase = autogenBuildDir + "/"; + rccOutBase += fpathCheckSum.getPart(absFile); + rccOutBase += "/qrc_"; + rccOutBase += cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile); - rccOut += ".cpp"; - - // Register rcc output file as generated - autogenProvides.push_back(rccOut); + // Register rcc ouput file as generated + for (std::vector<std::string>::const_iterator it = + suffixes.begin(); + it != suffixes.end(); ++it) { + std::string rccOutCfg = rccOutBase; + rccOutCfg += *it; + rccOutCfg += ".cpp"; + AddGeneratedSource(makefile, rccOutCfg, + cmQtAutoGeneratorCommon::RCC); + autogenProvides.push_back(rccOutCfg); + } // Add rcc output file to origin target sources - { - cmSourceFile* gFile = makefile->GetOrCreateSource(rccOut, true); - gFile->SetProperty("SKIP_AUTOGEN", "On"); + if (multiConfig) { + target->AddSource(rccOutBase + "_$<CONFIG>.cpp"); + } else { + target->AddSource(rccOutBase + ".cpp"); } - target->AddSource(rccOut); - AddToSourceGroup(makefile, rccOut, cmQtAutoGeneratorCommon::RCC); } if (PropertyEnabled(sf, "GENERATED")) { @@ -889,9 +965,25 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( cmMakefile::ScopePushPop varScope(makefile); static_cast<void>(varScope); + // Get configurations + std::string config; + const std::vector<std::string> configs(GetConfigurations(makefile, &config)); + + // Configurations settings buffers + std::map<std::string, std::string> configSuffix; std::map<std::string, std::string> configMocIncludes; std::map<std::string, std::string> configMocDefines; std::map<std::string, std::string> configUicOptions; + + // Configuration suffix + if (IsMultiConfig(target->GetGlobalGenerator())) { + for (std::vector<std::string>::const_iterator it = configs.begin(); + it != configs.end(); ++it) { + configSuffix[*it] = "_" + *it; + } + } + + // Basic setup { const bool mocEnabled = target->GetPropertyAsBool("AUTOMOC"); const bool uicEnabled = target->GetPropertyAsBool("AUTOUIC"); @@ -899,45 +991,46 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( const std::string autogenTargetName = GetAutogenTargetName(target); const std::string qtMajorVersion = GetQtMajorVersion(target); - std::vector<std::string> _sources; - std::vector<std::string> _headers; + std::vector<std::string> sources; + std::vector<std::string> headers; if (mocEnabled || uicEnabled || rccEnabled) { std::vector<std::string> mocSkipList; std::vector<std::string> uicSkipList; - AcquireScanFiles(target, _sources, _headers, mocSkipList, uicSkipList); + AcquireScanFiles(target, sources, headers, mocSkipList, uicSkipList); if (mocEnabled) { - MocSetupAutoTarget(target, autogenTargetName, qtMajorVersion, - mocSkipList, configMocIncludes, configMocDefines); + MocSetupAutoTarget(target, autogenTargetName, qtMajorVersion, config, + configs, mocSkipList, configMocIncludes, + configMocDefines); } if (uicEnabled) { - UicSetupAutoTarget(target, qtMajorVersion, uicSkipList, - configUicOptions); + UicSetupAutoTarget(target, qtMajorVersion, config, configs, + uicSkipList, configUicOptions); } if (rccEnabled) { RccSetupAutoTarget(target, qtMajorVersion); } } - AddDefinitionEscaped(makefile, "_autogen_target_name", autogenTargetName); - AddDefinitionEscaped(makefile, "_origin_target_name", target->GetName()); + AddDefinitionEscaped(makefile, "_autogen_build_dir", + GetAutogenTargetBuildDir(target)); AddDefinitionEscaped(makefile, "_qt_version_major", qtMajorVersion); - AddDefinitionEscaped(makefile, "_sources", _sources); - AddDefinitionEscaped(makefile, "_headers", _headers); + AddDefinitionEscaped(makefile, "_sources", sources); + AddDefinitionEscaped(makefile, "_headers", headers); } - // Generate config file - std::string inputFile = cmSystemTools::GetCMakeRoot(); - inputFile += "/Modules/AutogenInfo.cmake.in"; - std::string outputFile = GetAutogenTargetFilesDir(target); - outputFile += "/AutogenInfo.cmake"; - - makefile->ConfigureFile(inputFile.c_str(), outputFile.c_str(), false, true, - false); + // Generate info file + std::string infoFile = GetAutogenTargetFilesDir(target); + infoFile += "/AutogenInfo.cmake"; + { + std::string inf = cmSystemTools::GetCMakeRoot(); + inf += "/Modules/AutogenInfo.cmake.in"; + makefile->ConfigureFile(inf.c_str(), infoFile.c_str(), false, true, false); + } - // Append custom config definitions to info file - if (!configMocDefines.empty() || !configMocIncludes.empty() || - !configUicOptions.empty()) { + // Append custom definitions to info file on demand + if (!configSuffix.empty() || !configMocDefines.empty() || + !configMocIncludes.empty() || !configUicOptions.empty()) { // Ensure we have write permission in case .in was read-only. mode_t perm = 0; @@ -946,46 +1039,49 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( #else mode_t mode_write = S_IWUSR; #endif - cmSystemTools::GetPermissions(outputFile, perm); + cmSystemTools::GetPermissions(infoFile, perm); if (!(perm & mode_write)) { - cmSystemTools::SetPermissions(outputFile, perm | mode_write); + cmSystemTools::SetPermissions(infoFile, perm | mode_write); } - cmsys::ofstream infoFile(outputFile.c_str(), std::ios::app); - if (!infoFile) { - std::string error = "Internal CMake error when trying to open file: "; - error += outputFile; - error += " for writing."; - cmSystemTools::Error(error.c_str()); - } else { - infoFile << "# Configuration specific options\n"; - if (!configMocDefines.empty()) { - for (std::map<std::string, std::string>::iterator - it = configMocDefines.begin(), - end = configMocDefines.end(); - it != end; ++it) { - infoFile << "set(AM_MOC_DEFINITIONS_" << it->first << " " - << it->second << ")\n"; - } + // Open and write file + cmsys::ofstream ofs(infoFile.c_str(), std::ios::app); + if (ofs) { + ofs << "# Configuration specific options\n"; + for (std::map<std::string, std::string>::iterator + it = configSuffix.begin(), + end = configSuffix.end(); + it != end; ++it) { + ofs << "set(AM_CONFIG_SUFFIX_" << it->first << " " << it->second + << ")\n"; } - if (!configMocIncludes.empty()) { - for (std::map<std::string, std::string>::iterator - it = configMocIncludes.begin(), - end = configMocIncludes.end(); - it != end; ++it) { - infoFile << "set(AM_MOC_INCLUDES_" << it->first << " " << it->second - << ")\n"; - } + for (std::map<std::string, std::string>::iterator + it = configMocDefines.begin(), + end = configMocDefines.end(); + it != end; ++it) { + ofs << "set(AM_MOC_DEFINITIONS_" << it->first << " " << it->second + << ")\n"; } - if (!configUicOptions.empty()) { - for (std::map<std::string, std::string>::iterator - it = configUicOptions.begin(), - end = configUicOptions.end(); - it != end; ++it) { - infoFile << "set(AM_UIC_TARGET_OPTIONS_" << it->first << " " - << it->second << ")\n"; - } + for (std::map<std::string, std::string>::iterator + it = configMocIncludes.begin(), + end = configMocIncludes.end(); + it != end; ++it) { + ofs << "set(AM_MOC_INCLUDES_" << it->first << " " << it->second + << ")\n"; + } + for (std::map<std::string, std::string>::iterator + it = configUicOptions.begin(), + end = configUicOptions.end(); + it != end; ++it) { + ofs << "set(AM_UIC_TARGET_OPTIONS_" << it->first << " " << it->second + << ")\n"; } + } else { + // File open error + std::string error = "Internal CMake error when trying to open file: "; + error += cmQtAutoGeneratorCommon::Quoted(infoFile); + error += " for writing."; + cmSystemTools::Error(error.c_str()); } } } diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index d40e809..27e4928 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -78,8 +78,8 @@ static void InfoGet(cmMakefile* makefile, const char* key, cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list); } -static void InfoGet(cmMakefile* makefile, const char* key, - const std::string& config, std::vector<std::string>& list) +static void InfoGetConfig(cmMakefile* makefile, const char* key, + const std::string& config, std::string& value) { const char* valueConf = CM_NULLPTR; { @@ -93,7 +93,16 @@ static void InfoGet(cmMakefile* makefile, const char* key, if (valueConf == CM_NULLPTR) { valueConf = makefile->GetSafeDefinition(key); } - cmSystemTools::ExpandListArgument(valueConf, list); + value = valueConf; +} + +static void InfoGetConfig(cmMakefile* makefile, const char* key, + const std::string& config, + std::vector<std::string>& list) +{ + std::string value; + InfoGetConfig(makefile, key, config, value); + cmSystemTools::ExpandListArgument(value, list); } inline static bool SettingsMatch(cmMakefile* makefile, const char* key, @@ -270,6 +279,7 @@ cmQtAutoGenerators::cmQtAutoGenerators() } } + // Moc macro filters this->MocMacroFilters[0].first = "Q_OBJECT"; this->MocMacroFilters[0].second.compile("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]"); this->MocMacroFilters[1].first = "Q_GADGET"; @@ -358,12 +368,13 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( { this->SettingsFile = cmSystemTools::CollapseFullPath(targetDirectory); cmSystemTools::ConvertToUnixSlashes(this->SettingsFile); - this->SettingsFile += "/AutogenOldSettings.cmake"; + this->SettingsFile += "/AutogenOldSettings"; + this->SettingsFile += this->ConfigSuffix; + this->SettingsFile += ".cmake"; } - // - Target names - InfoGet(makefile, "AM_TARGET_NAME", this->AutogenTargetName); - InfoGet(makefile, "AM_ORIGIN_TARGET_NAME", this->OriginTargetName); + // -- Meta + InfoGetConfig(makefile, "AM_CONFIG_SUFFIX", config, this->ConfigSuffix); // - Files and directories InfoGet(makefile, "AM_CMAKE_SOURCE_DIR", this->ProjectSourceDir); @@ -372,6 +383,11 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( InfoGet(makefile, "AM_CMAKE_CURRENT_BINARY_DIR", this->CurrentBinaryDir); InfoGet(makefile, "AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE", this->IncludeProjectDirsBefore); + InfoGet(makefile, "AM_BUILD_DIR", this->AutogenBuildDir); + if (this->AutogenBuildDir.empty()) { + this->LogError("AutoGen: Error: Missing autogen build directory "); + return false; + } InfoGet(makefile, "AM_SOURCES", this->Sources); InfoGet(makefile, "AM_HEADERS", this->Headers); @@ -395,7 +411,8 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( // - Moc if (this->MocEnabled()) { InfoGet(makefile, "AM_MOC_SKIP", this->MocSkipList); - InfoGet(makefile, "AM_MOC_DEFINITIONS", config, this->MocDefinitions); + InfoGetConfig(makefile, "AM_MOC_DEFINITIONS", config, + this->MocDefinitions); #ifdef _WIN32 { const std::string win32("WIN32"); @@ -404,7 +421,7 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( } } #endif - InfoGet(makefile, "AM_MOC_INCLUDES", config, this->MocIncludePaths); + InfoGetConfig(makefile, "AM_MOC_INCLUDES", config, this->MocIncludePaths); InfoGet(makefile, "AM_MOC_OPTIONS", this->MocOptions); InfoGet(makefile, "AM_MOC_RELAXED_MODE", this->MocRelaxedMode); { @@ -439,7 +456,8 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( if (this->UicEnabled()) { InfoGet(makefile, "AM_UIC_SKIP", this->UicSkipList); InfoGet(makefile, "AM_UIC_SEARCH_PATHS", this->UicSearchPaths); - InfoGet(makefile, "AM_UIC_TARGET_OPTIONS", config, this->UicTargetOptions); + InfoGetConfig(makefile, "AM_UIC_TARGET_OPTIONS", config, + this->UicTargetOptions); { std::vector<std::string> uicFilesVec; std::vector<std::string> uicOptionsVec; @@ -615,18 +633,23 @@ bool cmQtAutoGenerators::SettingsFileWrite() void cmQtAutoGenerators::Init(cmMakefile* makefile) { - this->AutogenBuildSubDir = this->AutogenTargetName; - this->AutogenBuildSubDir += "/"; - - this->MocCppFilenameRel = this->AutogenBuildSubDir; - this->MocCppFilenameRel += "moc_compilation.cpp"; - - this->MocCppFilenameAbs = this->CurrentBinaryDir + this->MocCppFilenameRel; + // Mocs compilation file + this->MocCompFileRel = "mocs_compilation"; + this->MocCompFileRel += this->ConfigSuffix; + this->MocCompFileRel += ".cpp"; + this->MocCompFileAbs = cmSystemTools::CollapseCombinedPath( + this->AutogenBuildDir, this->MocCompFileRel); + + // Mocs include directory + this->AutogenIncludeDir = "include"; + this->AutogenIncludeDir += this->ConfigSuffix; + this->AutogenIncludeDir += "/"; // Moc predefs file if (!this->MocPredefsCmd.empty()) { - this->MocPredefsFileRel = this->AutogenBuildSubDir + "moc_predefs.h"; - this->MocPredefsFileAbs = this->CurrentBinaryDir + this->MocPredefsFileRel; + this->MocPredefsFileRel = "moc_predefs.h"; + this->MocPredefsFileAbs = cmSystemTools::CollapseCombinedPath( + this->AutogenBuildDir, this->MocPredefsFileRel); } // Init file path checksum generator @@ -699,10 +722,10 @@ bool cmQtAutoGenerators::RunAutogen() // the program goes through all .cpp files to see which moc files are // included. It is not really interesting how the moc file is named, but // what file the moc is created from. Once a moc is included the same moc - // may not be included in the moc_compilation.cpp file anymore. OTOH if - // there's a header containing Q_OBJECT where no corresponding moc file - // is included anywhere a moc_<filename>.cpp file is created and included - // in the moc_compilation.cpp file. + // may not be included in the mocs_compilation_$<CONFIG>.cpp file anymore. + // OTOH if there's a header containing Q_OBJECT where no corresponding + // moc file is included anywhere a moc_<filename>.cpp file is created and + // included in the mocs_compilation_$<CONFIG>.cpp file. // key = moc source filepath, value = moc output filepath std::map<std::string, std::string> mocsIncluded; @@ -1107,7 +1130,7 @@ void cmQtAutoGenerators::MocParseHeaderContent( if (this->MocRequired(contentText)) { // Register moc job mocsNotIncluded[absFilename] = - this->ChecksumedPath(absFilename, "moc_", ".cpp"); + this->ChecksumedPath(absFilename, "moc_", this->ConfigSuffix + ".cpp"); this->MocFindDepends(absFilename, contentText, mocDepends); } } @@ -1257,37 +1280,31 @@ bool cmQtAutoGenerators::MocGenerateAll( } // Generate moc files that are included by source files. - { - const std::string subDir = "include/"; - for (std::map<std::string, std::string>::const_iterator it = - mocsIncluded.begin(); - it != mocsIncluded.end(); ++it) { - if (!this->MocGenerateFile(it->first, it->second, subDir, mocDepends)) { - if (this->MocRunFailed) { - return false; - } + for (std::map<std::string, std::string>::const_iterator it = + mocsIncluded.begin(); + it != mocsIncluded.end(); ++it) { + if (!this->MocGenerateFile(it->first, it->second, mocDepends, true)) { + if (this->MocRunFailed) { + return false; } } } // Generate moc files that are _not_ included by source files. bool mocCompFileGenerated = false; - { - const std::string subDir; - for (std::map<std::string, std::string>::const_iterator it = - mocsNotIncluded.begin(); - it != mocsNotIncluded.end(); ++it) { - if (this->MocGenerateFile(it->first, it->second, subDir, mocDepends)) { - mocCompFileGenerated = true; - } else { - if (this->MocRunFailed) { - return false; - } + for (std::map<std::string, std::string>::const_iterator it = + mocsNotIncluded.begin(); + it != mocsNotIncluded.end(); ++it) { + if (this->MocGenerateFile(it->first, it->second, mocDepends, false)) { + mocCompFileGenerated = true; + } else { + if (this->MocRunFailed) { + return false; } } } - // Compose moc_compilation.cpp content + // Compose mocs compilation file content std::string automocSource; { std::ostringstream ost; @@ -1306,18 +1323,18 @@ bool cmQtAutoGenerators::MocGenerateAll( automocSource = ost.str(); } - if (this->FileDiffers(this->MocCppFilenameAbs, automocSource)) { - // Actually write moc_compilation.cpp - this->LogBold("Generating MOC compilation " + this->MocCppFilenameRel); - if (!this->FileWrite("AutoMoc", this->MocCppFilenameAbs, automocSource)) { + if (this->FileDiffers(this->MocCompFileAbs, automocSource)) { + // Actually write mocs compilation file + this->LogBold("Generating MOC compilation " + this->MocCompFileRel); + if (!this->FileWrite("AutoMoc", this->MocCompFileAbs, automocSource)) { return false; } } else if (mocCompFileGenerated) { - // Only touch moc_compilation.cpp + // Only touch mocs compilation file if (this->Verbose) { - this->LogInfo("Touching MOC compilation " + this->MocCppFilenameRel); + this->LogInfo("Touching MOC compilation " + this->MocCompFileRel); } - cmSystemTools::Touch(this->MocCppFilenameAbs, false); + cmSystemTools::Touch(this->MocCompFileAbs, false); } return true; @@ -1328,15 +1345,16 @@ bool cmQtAutoGenerators::MocGenerateAll( */ bool cmQtAutoGenerators::MocGenerateFile( const std::string& sourceFile, const std::string& mocFileName, - const std::string& subDir, - const std::map<std::string, std::set<std::string> >& mocDepends) + const std::map<std::string, std::set<std::string> >& mocDepends, + bool included) { bool mocGenerated = false; bool generateMoc = this->MocSettingsChanged || this->MocPredefsChanged; const std::string mocFileRel = - this->AutogenBuildSubDir + subDir + mocFileName; - const std::string mocFileAbs = this->CurrentBinaryDir + mocFileRel; + included ? (this->AutogenIncludeDir + mocFileName) : mocFileName; + const std::string mocFileAbs = + cmSystemTools::CollapseCombinedPath(this->AutogenBuildDir, mocFileRel); if (!generateMoc) { // Test if the source file is newer that the build file @@ -1524,9 +1542,9 @@ bool cmQtAutoGenerators::UicGenerateFile(const std::string& realName, bool uicGenerated = false; bool generateUic = this->UicSettingsChanged; - const std::string uicFileRel = - this->AutogenBuildSubDir + "include/" + uiOutputFile; - const std::string uicFileAbs = this->CurrentBinaryDir + uicFileRel; + const std::string uicFileRel = this->AutogenIncludeDir + uiOutputFile; + const std::string uicFileAbs = + cmSystemTools::CollapseCombinedPath(this->AutogenBuildDir, uicFileRel); if (!generateUic) { // Test if the source file is newer that the build file @@ -1590,12 +1608,17 @@ bool cmQtAutoGenerators::RccGenerateAll() // generate single map with input / output names std::map<std::string, std::string> qrcGenMap; - for (std::vector<std::string>::const_iterator si = this->RccSources.begin(); - si != this->RccSources.end(); ++si) { - const std::string ext = cmsys::SystemTools::GetFilenameLastExtension(*si); - if (ext == ".qrc") { - qrcGenMap[*si] = - this->AutogenBuildSubDir + this->ChecksumedPath(*si, "qrc_", ".cpp"); + { + const std::string qrcPrefix = "qrc_"; + const std::string qrcSuffix = this->ConfigSuffix + ".cpp"; + for (std::vector<std::string>::const_iterator si = + this->RccSources.begin(); + si != this->RccSources.end(); ++si) { + const std::string ext = + cmsys::SystemTools::GetFilenameLastExtension(*si); + if (ext == ".qrc") { + qrcGenMap[*si] = this->ChecksumedPath(*si, qrcPrefix, qrcSuffix); + } } } @@ -1636,7 +1659,8 @@ bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile, bool rccGenerated = false; bool generateRcc = this->RccSettingsChanged; - const std::string rccBuildFile = this->CurrentBinaryDir + rccOutputFile; + const std::string rccBuildFile = + cmSystemTools::CollapseCombinedPath(this->AutogenBuildDir, rccOutputFile); if (!generateRcc) { // Test if the resources list file is newer than build file @@ -1827,9 +1851,9 @@ bool cmQtAutoGenerators::NameCollisionTest( * @brief Generates a file path based on the checksum of the source file path * @return The path */ -std::string cmQtAutoGenerators::ChecksumedPath(const std::string& sourceFile, - const char* basePrefix, - const char* baseSuffix) const +std::string cmQtAutoGenerators::ChecksumedPath( + const std::string& sourceFile, const std::string& basePrefix, + const std::string& baseSuffix) const { std::string res = FPathChecksum.getPart(sourceFile); res += "/"; diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index 987110f..b525364 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -107,8 +107,8 @@ private: const std::map<std::string, std::set<std::string> >& mocDepends); bool MocGenerateFile( const std::string& sourceFile, const std::string& mocFileName, - const std::string& subDir, - const std::map<std::string, std::set<std::string> >& mocDepends); + const std::map<std::string, std::set<std::string> >& mocDepends, + bool included); // -- Uic file generation bool UicFindIncludedFile(std::string& absFile, const std::string& sourceFile, @@ -139,8 +139,8 @@ private: const std::map<std::string, std::string>& genFiles, std::multimap<std::string, std::string>& collisions) const; std::string ChecksumedPath(const std::string& sourceFile, - const char* basePrefix, - const char* baseSuffix) const; + const std::string& basePrefix, + const std::string& baseSuffix) const; bool MakeParentDirectory(const char* logPrefix, const std::string& filename) const; bool FileDiffers(const std::string& filename, const std::string& content); @@ -157,15 +157,15 @@ private: bool MocFindIncludedFile(std::string& absFile, const std::string& sourceFile, const std::string& includeString) const; - // -- Target names - std::string OriginTargetName; - std::string AutogenTargetName; + // -- Meta + std::string ConfigSuffix; // -- Directories std::string ProjectSourceDir; std::string ProjectBinaryDir; std::string CurrentSourceDir; std::string CurrentBinaryDir; - std::string AutogenBuildSubDir; + std::string AutogenBuildDir; + std::string AutogenIncludeDir; // -- Qt environment std::string QtMajorVersion; std::string MocExecutable; @@ -189,8 +189,8 @@ private: bool MocPredefsChanged; bool MocRelaxedMode; bool MocRunFailed; - std::string MocCppFilenameRel; - std::string MocCppFilenameAbs; + std::string MocCompFileRel; + std::string MocCompFileAbs; std::string MocPredefsFileRel; std::string MocPredefsFileAbs; std::vector<std::string> MocSkipList; diff --git a/Tests/QtAutoUicInterface/CMakeLists.txt b/Tests/QtAutoUicInterface/CMakeLists.txt index 70175fb..3ea1294 100644 --- a/Tests/QtAutoUicInterface/CMakeLists.txt +++ b/Tests/QtAutoUicInterface/CMakeLists.txt @@ -53,6 +53,12 @@ set_property(TARGET KI18n APPEND PROPERTY # END upstream +if(${CMAKE_GENERATOR} MATCHES "Visual Studio") +set(INC_DIR "include_${CMAKE_BUILD_TYPE}" ) +else() +set(INC_DIR "include" ) +endif() + add_library(LibWidget libwidget.cpp) target_link_libraries(LibWidget KI18n ${QT_GUI_TARGET}) set_property(TARGET LibWidget PROPERTY NO_KUIT_SEMANTIC ON) @@ -64,6 +70,6 @@ target_link_libraries(MyWidget KI18n ${QT_GUI_TARGET}) add_executable(QtAutoUicInterface main.cpp) target_compile_definitions(QtAutoUicInterface PRIVATE - UI_LIBWIDGET_H="${CMAKE_CURRENT_BINARY_DIR}/LibWidget_autogen/include/ui_libwidget.h" - UI_MYWIDGET_H="${CMAKE_CURRENT_BINARY_DIR}/MyWidget_autogen/include/ui_mywidget.h" + UI_LIBWIDGET_H="${CMAKE_CURRENT_BINARY_DIR}/LibWidget_autogen/${INC_DIR}/ui_libwidget.h" + UI_MYWIDGET_H="${CMAKE_CURRENT_BINARY_DIR}/MyWidget_autogen/${INC_DIR}/ui_mywidget.h" ) diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt index 618f79d..3252e3d 100644 --- a/Utilities/cmlibuv/CMakeLists.txt +++ b/Utilities/cmlibuv/CMakeLists.txt @@ -164,7 +164,10 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") src/unix/linux-inotify.c src/unix/linux-syscalls.c src/unix/linux-syscalls.h + src/unix/procfs-exepath.c src/unix/proctitle.c + src/unix/sysinfo-loadavg.c + src/unix/sysinfo-memory.c ) endif() @@ -249,6 +252,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "SunOS") ) endif() list(APPEND uv_sources + src/unix/no-proctitle.c src/unix/sunos.c ) endif() diff --git a/Utilities/cmlibuv/include/uv-posix.h b/Utilities/cmlibuv/include/uv-posix.h new file mode 100644 index 0000000..9a96634 --- /dev/null +++ b/Utilities/cmlibuv/include/uv-posix.h @@ -0,0 +1,31 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_POSIX_H +#define UV_POSIX_H + +#define UV_PLATFORM_LOOP_FIELDS \ + struct pollfd* poll_fds; \ + size_t poll_fds_used; \ + size_t poll_fds_size; \ + unsigned char poll_fds_iterating; \ + +#endif /* UV_POSIX_H */ diff --git a/Utilities/cmlibuv/include/uv-unix.h b/Utilities/cmlibuv/include/uv-unix.h index 5440729..d775450 100644 --- a/Utilities/cmlibuv/include/uv-unix.h +++ b/Utilities/cmlibuv/include/uv-unix.h @@ -60,6 +60,8 @@ defined(__OpenBSD__) || \ defined(__NetBSD__) # include "uv-bsd.h" +#elif defined(__CYGWIN__) || defined(__MSYS__) +# include "uv-posix.h" #endif #ifndef PTHREAD_BARRIER_SERIAL_THREAD diff --git a/Utilities/cmlibuv/include/uv.h b/Utilities/cmlibuv/include/uv.h index ce04875..38f5676 100644 --- a/Utilities/cmlibuv/include/uv.h +++ b/Utilities/cmlibuv/include/uv.h @@ -1082,6 +1082,8 @@ UV_EXTERN int uv_os_getenv(const char* name, char* buffer, size_t* size); UV_EXTERN int uv_os_setenv(const char* name, const char* value); UV_EXTERN int uv_os_unsetenv(const char* name); +UV_EXTERN int uv_os_gethostname(char* buffer, size_t* size); + typedef enum { UV_FS_UNKNOWN = -1, diff --git a/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c b/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c index 0b5653d..4147894 100644 --- a/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c +++ b/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c @@ -27,7 +27,9 @@ #include <ifaddrs.h> #include <net/if.h> +#if !defined(__CYGWIN__) && !defined(__MSYS__) #include <net/if_dl.h> +#endif static int uv__ifaddr_exclude(struct ifaddrs *ent) { if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) @@ -107,9 +109,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { for (i = 0; i < *count; i++) { if (strcmp(address->name, ent->ifa_name) == 0) { +#if defined(__CYGWIN__) || defined(__MSYS__) + memset(address->phys_addr, 0, sizeof(address->phys_addr)); +#else struct sockaddr_dl* sa_addr; sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); +#endif } address++; } diff --git a/Utilities/cmlibuv/src/unix/core.c b/Utilities/cmlibuv/src/unix/core.c index 96495b8..30cdaef 100644 --- a/Utilities/cmlibuv/src/unix/core.c +++ b/Utilities/cmlibuv/src/unix/core.c @@ -28,6 +28,7 @@ #include <errno.h> #include <assert.h> #include <unistd.h> +#include <sys/param.h> /* MAXHOSTNAMELEN on Linux and the BSDs */ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -42,6 +43,7 @@ #include <pwd.h> #ifdef __sun +# include <netdb.h> /* MAXHOSTNAMELEN on Solaris */ # include <sys/filio.h> # include <sys/types.h> # include <sys/wait.h> @@ -80,6 +82,11 @@ #include <sys/ioctl.h> #endif +/* Fallback for the maximum hostname length */ +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 256 +#endif + static int uv__run_pending(uv_loop_t* loop); /* Verify that uv_buf_t is ABI-compatible with struct iovec. */ @@ -538,6 +545,7 @@ int uv__nonblock_ioctl(int fd, int set) { } +#if !defined(__CYGWIN__) && !defined(__MSYS__) int uv__cloexec_ioctl(int fd, int set) { int r; @@ -550,6 +558,7 @@ int uv__cloexec_ioctl(int fd, int set) { return 0; } +#endif int uv__nonblock_fcntl(int fd, int set) { @@ -1285,3 +1294,33 @@ int uv_os_unsetenv(const char* name) { return 0; } + + +int uv_os_gethostname(char* buffer, size_t* size) { + /* + On some platforms, if the input buffer is not large enough, gethostname() + succeeds, but truncates the result. libuv can detect this and return ENOBUFS + instead by creating a large enough buffer and comparing the hostname length + to the size input. + */ + char buf[MAXHOSTNAMELEN + 1]; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + if (gethostname(buf, sizeof(buf)) != 0) + return -errno; + + buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */ + len = strlen(buf); + + if (len >= *size) { + *size = len + 1; + return -ENOBUFS; + } + + memcpy(buffer, buf, len + 1); + *size = len; + return 0; +} diff --git a/Utilities/cmlibuv/src/unix/cygwin.c b/Utilities/cmlibuv/src/unix/cygwin.c new file mode 100644 index 0000000..5a887dd --- /dev/null +++ b/Utilities/cmlibuv/src/unix/cygwin.c @@ -0,0 +1,54 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include <sys/sysinfo.h> +#include <unistd.h> + +int uv_uptime(double* uptime) { + struct sysinfo info; + + if (sysinfo(&info) < 0) + return -errno; + + *uptime = info.uptime; + return 0; +} + +int uv_resident_set_memory(size_t* rss) { + /* FIXME: read /proc/meminfo? */ + *rss = 0; + return UV_ENOSYS; +} + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + /* FIXME: read /proc/stat? */ + *cpu_infos = NULL; + *count = 0; + return UV_ENOSYS; +} + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + (void)cpu_infos; + (void)count; +} diff --git a/Utilities/cmlibuv/src/unix/fsevents.c b/Utilities/cmlibuv/src/unix/fsevents.c index d331a13..643e233 100644 --- a/Utilities/cmlibuv/src/unix/fsevents.c +++ b/Utilities/cmlibuv/src/unix/fsevents.c @@ -378,9 +378,6 @@ static void uv__fsevents_destroy_stream(uv_loop_t* loop) { if (state->fsevent_stream == NULL) return; - /* Flush all accumulated events */ - pFSEventStreamFlushSync(state->fsevent_stream); - /* Stop emitting events */ pFSEventStreamStop(state->fsevent_stream); diff --git a/Utilities/cmlibuv/src/unix/linux-core.c b/Utilities/cmlibuv/src/unix/linux-core.c index 646be4f..2866e93 100644 --- a/Utilities/cmlibuv/src/unix/linux-core.c +++ b/Utilities/cmlibuv/src/unix/linux-core.c @@ -472,55 +472,6 @@ uint64_t uv__hrtime(uv_clocktype_t type) { } -void uv_loadavg(double avg[3]) { - struct sysinfo info; - - if (sysinfo(&info) < 0) return; - - avg[0] = (double) info.loads[0] / 65536.0; - avg[1] = (double) info.loads[1] / 65536.0; - avg[2] = (double) info.loads[2] / 65536.0; -} - - -int uv_exepath(char* buffer, size_t* size) { - ssize_t n; - - if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; - - n = *size - 1; - if (n > 0) - n = readlink("/proc/self/exe", buffer, n); - - if (n == -1) - return -errno; - - buffer[n] = '\0'; - *size = n; - - return 0; -} - - -uint64_t uv_get_free_memory(void) { - struct sysinfo info; - - if (sysinfo(&info) == 0) - return (uint64_t) info.freeram * info.mem_unit; - return 0; -} - - -uint64_t uv_get_total_memory(void) { - struct sysinfo info; - - if (sysinfo(&info) == 0) - return (uint64_t) info.totalram * info.mem_unit; - return 0; -} - - int uv_resident_set_memory(size_t* rss) { char buf[1024]; const char* s; diff --git a/Utilities/cmlibuv/src/unix/no-fsevents.c b/Utilities/cmlibuv/src/unix/no-fsevents.c new file mode 100644 index 0000000..38fb6ab --- /dev/null +++ b/Utilities/cmlibuv/src/unix/no-fsevents.c @@ -0,0 +1,42 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include <errno.h> + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + return -ENOSYS; +} + +int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, + const char* filename, unsigned int flags) { + return -ENOSYS; +} + +int uv_fs_event_stop(uv_fs_event_t* handle) { + return -ENOSYS; +} + +void uv__fs_event_close(uv_fs_event_t* handle) { + UNREACHABLE(); +} diff --git a/Utilities/cmlibuv/src/unix/no-proctitle.c b/Utilities/cmlibuv/src/unix/no-proctitle.c new file mode 100644 index 0000000..a5c19fb --- /dev/null +++ b/Utilities/cmlibuv/src/unix/no-proctitle.c @@ -0,0 +1,42 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include <errno.h> +#include <stddef.h> + +char** uv_setup_args(int argc, char** argv) { + return argv; +} + +int uv_set_process_title(const char* title) { + return 0; +} + +int uv_get_process_title(char* buffer, size_t size) { + if (buffer == NULL || size == 0) + return -EINVAL; + + buffer[0] = '\0'; + return 0; +} diff --git a/Utilities/cmlibuv/src/unix/openbsd.c b/Utilities/cmlibuv/src/unix/openbsd.c index 7e4b253..56f0af1 100644 --- a/Utilities/cmlibuv/src/unix/openbsd.c +++ b/Utilities/cmlibuv/src/unix/openbsd.c @@ -30,7 +30,6 @@ #include <errno.h> #include <fcntl.h> -#include <kvm.h> #include <paths.h> #include <stdlib.h> #include <string.h> diff --git a/Utilities/cmlibuv/src/unix/os390.c b/Utilities/cmlibuv/src/unix/os390.c index e9ba90c..2ba5abf 100644 --- a/Utilities/cmlibuv/src/unix/os390.c +++ b/Utilities/cmlibuv/src/unix/os390.c @@ -663,28 +663,6 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { return 0; } - -void uv__fs_event_close(uv_fs_event_t* handle) { - UNREACHABLE(); -} - - -int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { - return -ENOSYS; -} - - -int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, - const char* filename, unsigned int flags) { - return -ENOSYS; -} - - -int uv_fs_event_stop(uv_fs_event_t* handle) { - return -ENOSYS; -} - - void uv__io_poll(uv_loop_t* loop, int timeout) { static const int max_safe_timeout = 1789569; struct epoll_event events[1024]; diff --git a/Utilities/cmlibuv/src/unix/pipe.c b/Utilities/cmlibuv/src/unix/pipe.c index 023e965..7ba1bf8 100644 --- a/Utilities/cmlibuv/src/unix/pipe.c +++ b/Utilities/cmlibuv/src/unix/pipe.c @@ -179,6 +179,14 @@ void uv_pipe_connect(uv_connect_t* req, if (r == -1 && errno != EINPROGRESS) { err = -errno; +#if defined(__CYGWIN__) || defined(__MSYS__) + /* EBADF is supposed to mean that the socket fd is bad, but + Cygwin reports EBADF instead of ENOTSOCK when the file is + not a socket. We do not expect to see a bad fd here + (e.g. due to new_sock), so translate the error. */ + if (err == -EBADF) + err = -ENOTSOCK; +#endif goto out; } diff --git a/Utilities/cmlibuv/src/unix/posix-poll.c b/Utilities/cmlibuv/src/unix/posix-poll.c new file mode 100644 index 0000000..3fba96e --- /dev/null +++ b/Utilities/cmlibuv/src/unix/posix-poll.c @@ -0,0 +1,324 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +/* POSIX defines poll() as a portable way to wait on file descriptors. + * Here we maintain a dynamically sized array of file descriptors and + * events to pass as the first argument to poll(). + */ + +#include <assert.h> +#include <stddef.h> +#include <stdint.h> +#include <errno.h> +#include <unistd.h> + +int uv__platform_loop_init(uv_loop_t* loop) { + loop->poll_fds = NULL; + loop->poll_fds_used = 0; + loop->poll_fds_size = 0; + loop->poll_fds_iterating = 0; + return 0; +} + +void uv__platform_loop_delete(uv_loop_t* loop) { + uv__free(loop->poll_fds); + loop->poll_fds = NULL; +} + +int uv__io_fork(uv_loop_t* loop) { + uv__platform_loop_delete(loop); + return uv__platform_loop_init(loop); +} + +/* Allocate or dynamically resize our poll fds array. */ +static void uv__pollfds_maybe_resize(uv_loop_t* loop) { + size_t i; + size_t n; + struct pollfd* p; + + if (loop->poll_fds_used < loop->poll_fds_size) + return; + + n = loop->poll_fds_size ? loop->poll_fds_size * 2 : 64; + p = uv__realloc(loop->poll_fds, n * sizeof(*loop->poll_fds)); + if (p == NULL) + abort(); + + loop->poll_fds = p; + for (i = loop->poll_fds_size; i < n; i++) { + loop->poll_fds[i].fd = -1; + loop->poll_fds[i].events = 0; + loop->poll_fds[i].revents = 0; + } + loop->poll_fds_size = n; +} + +/* Primitive swap operation on poll fds array elements. */ +static void uv__pollfds_swap(uv_loop_t* loop, size_t l, size_t r) { + struct pollfd pfd; + pfd = loop->poll_fds[l]; + loop->poll_fds[l] = loop->poll_fds[r]; + loop->poll_fds[r] = pfd; +} + +/* Add a watcher's fd to our poll fds array with its pending events. */ +static void uv__pollfds_add(uv_loop_t* loop, uv__io_t* w) { + size_t i; + struct pollfd* pe; + + /* If the fd is already in the set just update its events. */ + assert(!loop->poll_fds_iterating); + for (i = 0; i < loop->poll_fds_used; ++i) { + if (loop->poll_fds[i].fd == w->fd) { + loop->poll_fds[i].events = w->pevents; + return; + } + } + + /* Otherwise, allocate a new slot in the set for the fd. */ + uv__pollfds_maybe_resize(loop); + pe = &loop->poll_fds[loop->poll_fds_used++]; + pe->fd = w->fd; + pe->events = w->pevents; +} + +/* Remove a watcher's fd from our poll fds array. */ +static void uv__pollfds_del(uv_loop_t* loop, int fd) { + size_t i; + assert(!loop->poll_fds_iterating); + for (i = 0; i < loop->poll_fds_used; ++i) { + if (loop->poll_fds[i].fd == fd) { + /* swap to last position and remove */ + --loop->poll_fds_used; + uv__pollfds_swap(loop, i, loop->poll_fds_used); + loop->poll_fds[loop->poll_fds_used].fd = -1; + loop->poll_fds[loop->poll_fds_used].events = 0; + loop->poll_fds[loop->poll_fds_used].revents = 0; + return; + } + } +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + sigset_t* pset; + sigset_t set; + uint64_t time_base; + uint64_t time_diff; + QUEUE* q; + uv__io_t* w; + size_t i; + unsigned int nevents; + int nfds; + int have_signals; + struct pollfd* pe; + int fd; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + /* Take queued watchers and add their fds to our poll fds array. */ + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + q = QUEUE_HEAD(&loop->watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + assert(w->pevents != 0); + assert(w->fd >= 0); + assert(w->fd < (int) loop->nwatchers); + + uv__pollfds_add(loop, w); + + w->events = w->pevents; + } + + /* Prepare a set of signals to block around poll(), if any. */ + pset = NULL; + if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { + pset = &set; + sigemptyset(pset); + sigaddset(pset, SIGPROF); + } + + assert(timeout >= -1); + time_base = loop->time; + + /* Loop calls to poll() and processing of results. If we get some + * results from poll() but they turn out not to be interesting to + * our caller then we need to loop around and poll() again. + */ + for (;;) { + if (pset != NULL) + if (pthread_sigmask(SIG_BLOCK, pset, NULL)) + abort(); + nfds = poll(loop->poll_fds, (nfds_t)loop->poll_fds_used, timeout); + if (pset != NULL) + if (pthread_sigmask(SIG_UNBLOCK, pset, NULL)) + abort(); + + /* Update loop->time unconditionally. It's tempting to skip the update when + * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the + * operating system didn't reschedule our process while in the syscall. + */ + SAVE_ERRNO(uv__update_time(loop)); + + if (nfds == 0) { + assert(timeout != -1); + return; + } + + if (nfds == -1) { + if (errno != EINTR) + abort(); + + if (timeout == -1) + continue; + + if (timeout == 0) + return; + + /* Interrupted by a signal. Update timeout and poll again. */ + goto update_timeout; + } + + /* Tell uv__platform_invalidate_fd not to manipulate our array + * while we are iterating over it. + */ + loop->poll_fds_iterating = 1; + + /* Initialize a count of events that we care about. */ + nevents = 0; + have_signals = 0; + + /* Loop over the entire poll fds array looking for returned events. */ + for (i = 0; i < loop->poll_fds_used; i++) { + pe = loop->poll_fds + i; + fd = pe->fd; + + /* Skip invalidated events, see uv__platform_invalidate_fd. */ + if (fd == -1) + continue; + + assert(fd >= 0); + assert((unsigned) fd < loop->nwatchers); + + w = loop->watchers[fd]; + + if (w == NULL) { + /* File descriptor that we've stopped watching, ignore. */ + uv__platform_invalidate_fd(loop, fd); + continue; + } + + /* Filter out events that user has not requested us to watch + * (e.g. POLLNVAL). + */ + pe->revents &= w->pevents | POLLERR | POLLHUP; + + if (pe->revents != 0) { + /* Run signal watchers last. */ + if (w == &loop->signal_io_watcher) { + have_signals = 1; + } else { + w->cb(loop, w, pe->revents); + } + + nevents++; + } + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->poll_fds_iterating = 0; + + /* Purge invalidated fds from our poll fds array. */ + uv__pollfds_del(loop, -1); + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + if (nevents != 0) + return; + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + time_diff = loop->time - time_base; + if (time_diff >= (uint64_t) timeout) + return; + + timeout -= time_diff; + } +} + +/* Remove the given fd from our poll fds array because no one + * is interested in its events anymore. + */ +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + size_t i; + + if (loop->poll_fds_iterating) { + /* uv__io_poll is currently iterating. Just invalidate fd. */ + for (i = 0; i < loop->poll_fds_used; i++) + if (loop->poll_fds[i].fd == fd) { + loop->poll_fds[i].fd = -1; + loop->poll_fds[i].events = 0; + loop->poll_fds[i].revents = 0; + } + } else { + /* uv__io_poll is not iterating. Delete fd from the set. */ + uv__pollfds_del(loop, fd); + } +} + +/* Check whether the given fd is supported by poll(). */ +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct pollfd p[1]; + int rv; + + p[0].fd = fd; + p[0].events = POLLIN; + + do + rv = poll(p, 1, 0); + while (rv == -1 && (errno == EINTR || errno == EAGAIN)); + + if (rv == -1) + return -errno; + + if (p[0].revents & POLLNVAL) + return -EINVAL; + + return 0; +} diff --git a/Utilities/cmlibuv/src/unix/procfs-exepath.c b/Utilities/cmlibuv/src/unix/procfs-exepath.c new file mode 100644 index 0000000..5fdb611 --- /dev/null +++ b/Utilities/cmlibuv/src/unix/procfs-exepath.c @@ -0,0 +1,45 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include <stddef.h> +#include <unistd.h> + +int uv_exepath(char* buffer, size_t* size) { + ssize_t n; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + n = *size - 1; + if (n > 0) + n = readlink("/proc/self/exe", buffer, n); + + if (n == -1) + return -errno; + + buffer[n] = '\0'; + *size = n; + + return 0; +} diff --git a/Utilities/cmlibuv/src/unix/stream.c b/Utilities/cmlibuv/src/unix/stream.c index dbd04f2..7b23d16 100644 --- a/Utilities/cmlibuv/src/unix/stream.c +++ b/Utilities/cmlibuv/src/unix/stream.c @@ -390,7 +390,7 @@ failed_malloc: int uv__stream_open(uv_stream_t* stream, int fd, int flags) { -#if defined(__APPLE__) || defined(__MVS__) +#if defined(__APPLE__) int enable; #endif @@ -409,7 +409,7 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) { return -errno; } -#if defined(__APPLE__) || defined(__MVS__) +#if defined(__APPLE__) enable = 1; if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) && errno != ENOTSOCK && @@ -1173,6 +1173,11 @@ static void uv__read(uv_stream_t* stream) { uv__stream_osx_interrupt_select(stream); } stream->read_cb(stream, 0, &buf); +#if defined(__CYGWIN__) || defined(__MSYS__) + } else if (errno == ECONNRESET && stream->type == UV_NAMED_PIPE) { + uv__stream_eof(stream, &buf); + return; +#endif } else { /* Error. User should call uv_close(). */ stream->read_cb(stream, -errno, &buf); @@ -1405,6 +1410,12 @@ int uv_write2(uv_write_t* req, */ if (uv__handle_fd((uv_handle_t*) send_handle) < 0) return -EBADF; + +#if defined(__CYGWIN__) || defined(__MSYS__) + /* Cygwin recvmsg always sets msg_controllen to zero, so we cannot send it. + See https://github.com/mirror/newlib-cygwin/blob/86fc4bf0/winsup/cygwin/fhandler_socket.cc#L1736-L1743 */ + return -ENOSYS; +#endif } /* It's legal for write_queue_size > 0 even when the write_queue is empty; diff --git a/Utilities/cmlibuv/src/unix/sunos.c b/Utilities/cmlibuv/src/unix/sunos.c index d100263..041f3f3 100644 --- a/Utilities/cmlibuv/src/unix/sunos.c +++ b/Utilities/cmlibuv/src/unix/sunos.c @@ -549,25 +549,6 @@ void uv__fs_event_close(uv_fs_event_t* handle) { #endif /* defined(PORT_SOURCE_FILE) */ -char** uv_setup_args(int argc, char** argv) { - return argv; -} - - -int uv_set_process_title(const char* title) { - return 0; -} - - -int uv_get_process_title(char* buffer, size_t size) { - if (buffer == NULL || size == 0) - return -EINVAL; - - buffer[0] = '\0'; - return 0; -} - - int uv_resident_set_memory(size_t* rss) { psinfo_t psinfo; int err; diff --git a/Utilities/cmlibuv/src/unix/sysinfo-loadavg.c b/Utilities/cmlibuv/src/unix/sysinfo-loadavg.c new file mode 100644 index 0000000..ebad0e8 --- /dev/null +++ b/Utilities/cmlibuv/src/unix/sysinfo-loadavg.c @@ -0,0 +1,36 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include <stdint.h> +#include <sys/sysinfo.h> + +void uv_loadavg(double avg[3]) { + struct sysinfo info; + + if (sysinfo(&info) < 0) return; + + avg[0] = (double) info.loads[0] / 65536.0; + avg[1] = (double) info.loads[1] / 65536.0; + avg[2] = (double) info.loads[2] / 65536.0; +} diff --git a/Utilities/cmlibuv/src/unix/sysinfo-memory.c b/Utilities/cmlibuv/src/unix/sysinfo-memory.c new file mode 100644 index 0000000..23b4fc6 --- /dev/null +++ b/Utilities/cmlibuv/src/unix/sysinfo-memory.c @@ -0,0 +1,42 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include <stdint.h> +#include <sys/sysinfo.h> + +uint64_t uv_get_free_memory(void) { + struct sysinfo info; + + if (sysinfo(&info) == 0) + return (uint64_t) info.freeram * info.mem_unit; + return 0; +} + +uint64_t uv_get_total_memory(void) { + struct sysinfo info; + + if (sysinfo(&info) == 0) + return (uint64_t) info.totalram * info.mem_unit; + return 0; +} diff --git a/Utilities/cmlibuv/src/win/util.c b/Utilities/cmlibuv/src/win/util.c index 1d64d4c..d2e7f77 100644 --- a/Utilities/cmlibuv/src/win/util.c +++ b/Utilities/cmlibuv/src/win/util.c @@ -59,6 +59,14 @@ # define UNLEN 256 #endif +/* + Max hostname length. The Windows gethostname() documentation states that 256 + bytes will always be large enough to hold the null-terminated hostname. +*/ +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 256 +#endif + /* Maximum environment variable size, including the terminating null */ #define MAX_ENV_VAR_LENGTH 32767 @@ -1540,3 +1548,29 @@ int uv_os_unsetenv(const char* name) { return 0; } + + +int uv_os_gethostname(char* buffer, size_t* size) { + char buf[MAXHOSTNAMELEN + 1]; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + uv__once_init(); /* Initialize winsock */ + + if (gethostname(buf, sizeof(buf)) != 0) + return uv_translate_sys_error(WSAGetLastError()); + + buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */ + len = strlen(buf); + + if (len >= *size) { + *size = len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, buf, len + 1); + *size = len; + return 0; +} |