summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/command/add_custom_command.rst6
-rw-r--r--Help/manual/cmake-generator-expressions.7.rst42
-rw-r--r--Help/manual/cmake-properties.7.rst1
-rw-r--r--Help/manual/cmake-qt.7.rst3
-rw-r--r--Help/manual/cmake-variables.7.rst1
-rw-r--r--Help/manual/cmake.1.rst2
-rw-r--r--Help/prop_tgt/AUTOGEN_PARALLEL.rst21
-rw-r--r--Help/prop_tgt/AUTOMOC.rst6
-rw-r--r--Help/prop_tgt/AUTOUIC.rst3
-rw-r--r--Help/release/dev/CheckIncludeFile-required-libs.rst11
-rw-r--r--Help/release/dev/autogen-parallel.rst10
-rw-r--r--Help/release/dev/cache-newline.rst7
-rw-r--r--Help/release/dev/extend-compile-language-genex.rst15
-rw-r--r--Help/variable/CMAKE_AUTOGEN_PARALLEL.rst10
-rw-r--r--Help/variable/CMAKE_AUTOMOC_MACRO_NAMES.rst2
-rw-r--r--Help/variable/CMAKE_CROSSCOMPILING.rst26
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER_EXTERNAL_TOOLCHAIN.rst2
-rw-r--r--Modules/AutoRccInfo.cmake.in4
-rw-r--r--Modules/AutogenInfo.cmake.in1
-rw-r--r--Modules/CheckIncludeFile.cmake3
-rw-r--r--Modules/CheckIncludeFileCXX.cmake3
-rw-r--r--Modules/CheckIncludeFiles.cmake3
-rw-r--r--Modules/FindDoxygen.cmake5
-rw-r--r--Modules/FindJava.cmake34
-rw-r--r--Modules/FindOpenGL.cmake1
-rw-r--r--Modules/FindOpenMP.cmake2
-rw-r--r--Modules/FindPythonInterp.cmake3
-rw-r--r--Modules/FindTCL.cmake4
-rw-r--r--Modules/Platform/AIX-GNU.cmake4
-rw-r--r--Source/CMakeLists.txt4
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/CTest/cmProcess.cxx20
-rw-r--r--Source/CTest/cmProcess.h4
-rw-r--r--Source/cmCacheManager.cxx74
-rw-r--r--Source/cmCacheManager.h17
-rw-r--r--Source/cmGeneratorExpressionEvaluationFile.cxx4
-rw-r--r--Source/cmGeneratorExpressionNode.cxx37
-rw-r--r--Source/cmGlobalGenerator.cxx10
-rw-r--r--Source/cmGlobalGenerator.h4
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx12
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx43
-rw-r--r--Source/cmMakefile.cxx9
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx2
-rw-r--r--Source/cmQtAutoGen.cxx314
-rw-r--r--Source/cmQtAutoGen.h55
-rw-r--r--Source/cmQtAutoGenInitializer.cxx (renamed from Source/cmQtAutoGeneratorInitializer.cxx)201
-rw-r--r--Source/cmQtAutoGenInitializer.h (renamed from Source/cmQtAutoGeneratorInitializer.h)21
-rw-r--r--Source/cmQtAutoGenerator.cxx669
-rw-r--r--Source/cmQtAutoGenerator.h308
-rw-r--r--Source/cmQtAutoGeneratorMocUic.cxx3029
-rw-r--r--Source/cmQtAutoGeneratorMocUic.h510
-rw-r--r--Source/cmQtAutoGeneratorRcc.cxx719
-rw-r--r--Source/cmQtAutoGeneratorRcc.h97
-rw-r--r--Source/cmServerProtocol.cxx4
-rw-r--r--Source/cmSourceGroup.cxx49
-rw-r--r--Source/cmSourceGroup.h12
-rw-r--r--Source/cmState.cxx4
-rw-r--r--Source/cmState.h3
-rw-r--r--Source/cmTarget.cxx1
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx78
-rw-r--r--Source/cmVisualStudio10TargetGenerator.h22
-rw-r--r--Source/cmake.cxx2
-rw-r--r--Source/cmcmd.cxx2
-rw-r--r--Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt22
-rw-r--r--Tests/CMakeCommands/target_compile_definitions/consumer.c20
-rw-r--r--Tests/CMakeCommands/target_compile_definitions/consumer.cpp2
-rw-r--r--Tests/CMakeCommands/target_include_directories/CMakeLists.txt20
-rw-r--r--Tests/CMakeCommands/target_include_directories/consumer.c10
-rw-r--r--Tests/CMakeCommands/target_include_directories/consumer.cpp6
-rw-r--r--Tests/CudaOnly/WithDefs/CMakeLists.txt21
-rw-r--r--Tests/CudaOnly/WithDefs/inc_cuda/inc_cuda.h1
-rw-r--r--Tests/CudaOnly/WithDefs/main.notcu29
-rw-r--r--Tests/CudaOnly/WithDefs/main_for_vs.cu1
-rw-r--r--Tests/GeneratorExpression/CMakeLists.txt6
-rw-r--r--Tests/QtAutogen/CommonTests.cmake6
-rw-r--r--Tests/QtAutogen/MocInclude/EObjAExtra_p.hpp2
-rw-r--r--Tests/QtAutogen/MocInclude/EObjA_p.hpp2
-rw-r--r--Tests/QtAutogen/MocInclude/EObjB_p.hpp2
-rw-r--r--Tests/QtAutogen/MocInclude/LObjA_p.h2
-rw-r--r--Tests/QtAutogen/MocInclude/LObjB_p.h2
-rw-r--r--Tests/QtAutogen/MocInclude/ObjA_p.h2
-rw-r--r--Tests/QtAutogen/MocInclude/ObjB_p.h2
-rw-r--r--Tests/QtAutogen/MocInclude/subExtra/EObjBExtra_p.hpp2
-rw-r--r--Tests/QtAutogen/MocInclude/subGlobal/GObj_p.hpp2
-rw-r--r--Tests/QtAutogen/Parallel/CMakeLists.txt10
-rw-r--r--Tests/QtAutogen/Parallel/aaa/bbb/data.qrc6
-rw-r--r--Tests/QtAutogen/Parallel/aaa/bbb/item.cpp22
-rw-r--r--Tests/QtAutogen/Parallel/aaa/bbb/item.hpp18
-rw-r--r--Tests/QtAutogen/Parallel/aaa/data.qrc6
-rw-r--r--Tests/QtAutogen/Parallel/aaa/item.cpp22
-rw-r--r--Tests/QtAutogen/Parallel/aaa/item.hpp18
-rw-r--r--Tests/QtAutogen/Parallel/aaa/view.ui24
-rw-r--r--Tests/QtAutogen/Parallel/bbb/aaa/data.qrc6
-rw-r--r--Tests/QtAutogen/Parallel/bbb/aaa/item.cpp22
-rw-r--r--Tests/QtAutogen/Parallel/bbb/aaa/item.hpp18
-rw-r--r--Tests/QtAutogen/Parallel/bbb/data.qrc6
-rw-r--r--Tests/QtAutogen/Parallel/bbb/item.cpp23
-rw-r--r--Tests/QtAutogen/Parallel/bbb/item.hpp17
-rw-r--r--Tests/QtAutogen/Parallel/bbb/view.ui24
-rw-r--r--Tests/QtAutogen/Parallel/ccc/data.qrc6
-rw-r--r--Tests/QtAutogen/Parallel/ccc/item.cpp25
-rw-r--r--Tests/QtAutogen/Parallel/ccc/item.hpp18
-rw-r--r--Tests/QtAutogen/Parallel/ccc/view.ui24
-rw-r--r--Tests/QtAutogen/Parallel/data.qrc5
-rw-r--r--Tests/QtAutogen/Parallel/item.cpp20
-rw-r--r--Tests/QtAutogen/Parallel/item.hpp15
-rw-r--r--Tests/QtAutogen/Parallel/main.cpp16
-rw-r--r--Tests/QtAutogen/Parallel/parallel.cmake24
-rw-r--r--Tests/QtAutogen/Parallel/view.ui24
-rw-r--r--Tests/QtAutogen/Parallel1/CMakeLists.txt10
-rw-r--r--Tests/QtAutogen/Parallel2/CMakeLists.txt10
-rw-r--r--Tests/QtAutogen/Parallel3/CMakeLists.txt10
-rw-r--r--Tests/QtAutogen/Parallel4/CMakeLists.txt10
-rw-r--r--Tests/QtAutogen/ParallelAUTO/CMakeLists.txt10
-rw-r--r--Tests/RunCMake/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-result.txt1
-rw-r--r--Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-stderr-VS.txt9
-rw-r--r--Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-stderr-Xcode.txt9
-rw-r--r--Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions.cmake5
-rw-r--r--Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-result.txt1
-rw-r--r--Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-VS.txt9
-rw-r--r--Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-Xcode.txt9
-rw-r--r--Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories.cmake5
-rw-r--r--Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-result.txt1
-rw-r--r--Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-stderr-VS.txt7
-rw-r--r--Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-stderr-Xcode.txt7
-rw-r--r--Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions.cmake5
-rw-r--r--Tests/RunCMake/COMPILE_LANGUAGE-genex/RunCMakeTest.cmake23
-rw-r--r--Tests/RunCMake/COMPILE_LANGUAGE-genex/main.cpp5
-rw-r--r--Tests/RunCMake/CacheNewline/CMakeLists.txt (renamed from Tests/RunCMake/COMPILE_LANGUAGE-genex/CMakeLists.txt)2
-rw-r--r--Tests/RunCMake/CacheNewline/CacheNewline-check.cmake16
-rw-r--r--Tests/RunCMake/CacheNewline/CacheNewline-stderr.txt2
-rw-r--r--Tests/RunCMake/CacheNewline/CacheNewline.cmake5
-rw-r--r--Tests/RunCMake/CacheNewline/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/CacheNewline/cache-regex.txt6
-rw-r--r--Tests/RunCMake/GenerateExportHeader/GEH.cmake11
-rw-r--r--Tests/RunCMake/GenerateExportHeader/libshared/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/GenerateExportHeader/libstatic/CMakeLists.txt2
-rw-r--r--Utilities/IWYU/mapping.imp3
-rwxr-xr-xUtilities/Scripts/update-libuv.bash2
-rw-r--r--Utilities/cmlibuv/CMakeLists.txt3
-rw-r--r--Utilities/cmlibuv/LICENSE4
-rw-r--r--Utilities/cmlibuv/include/pthread-barrier.h1
-rw-r--r--Utilities/cmlibuv/include/uv-errno.h12
-rw-r--r--Utilities/cmlibuv/include/uv-os390.h3
-rw-r--r--Utilities/cmlibuv/include/uv-unix.h96
-rw-r--r--Utilities/cmlibuv/include/uv-version.h2
-rw-r--r--Utilities/cmlibuv/include/uv-win.h28
-rw-r--r--Utilities/cmlibuv/include/uv.h63
-rw-r--r--Utilities/cmlibuv/src/threadpool.c18
-rw-r--r--Utilities/cmlibuv/src/unix/aix-common.c292
-rw-r--r--Utilities/cmlibuv/src/unix/aix.c242
-rw-r--r--Utilities/cmlibuv/src/unix/android-ifaddrs.c49
-rw-r--r--Utilities/cmlibuv/src/unix/atomic-ops.h5
-rw-r--r--Utilities/cmlibuv/src/unix/bsd-ifaddrs.c23
-rw-r--r--Utilities/cmlibuv/src/unix/core.c45
-rw-r--r--Utilities/cmlibuv/src/unix/freebsd.c87
-rw-r--r--Utilities/cmlibuv/src/unix/fs.c177
-rw-r--r--Utilities/cmlibuv/src/unix/fsevents.c28
-rw-r--r--Utilities/cmlibuv/src/unix/getaddrinfo.c30
-rw-r--r--Utilities/cmlibuv/src/unix/ibmi.c112
-rw-r--r--Utilities/cmlibuv/src/unix/internal.h15
-rw-r--r--Utilities/cmlibuv/src/unix/kqueue.c38
-rw-r--r--Utilities/cmlibuv/src/unix/linux-core.c14
-rw-r--r--Utilities/cmlibuv/src/unix/loop.c2
-rw-r--r--Utilities/cmlibuv/src/unix/netbsd.c57
-rw-r--r--Utilities/cmlibuv/src/unix/openbsd.c33
-rw-r--r--Utilities/cmlibuv/src/unix/os390-syscalls.c229
-rw-r--r--Utilities/cmlibuv/src/unix/os390-syscalls.h3
-rw-r--r--Utilities/cmlibuv/src/unix/os390.c175
-rw-r--r--Utilities/cmlibuv/src/unix/pipe.c53
-rw-r--r--Utilities/cmlibuv/src/unix/poll.c25
-rw-r--r--Utilities/cmlibuv/src/unix/process.c42
-rw-r--r--Utilities/cmlibuv/src/unix/proctitle.c35
-rw-r--r--Utilities/cmlibuv/src/unix/pthread-barrier.c121
-rw-r--r--Utilities/cmlibuv/src/unix/stream.c39
-rw-r--r--Utilities/cmlibuv/src/unix/sunos.c4
-rw-r--r--Utilities/cmlibuv/src/unix/tcp.c101
-rw-r--r--Utilities/cmlibuv/src/unix/thread.c197
-rw-r--r--Utilities/cmlibuv/src/unix/tty.c36
-rw-r--r--Utilities/cmlibuv/src/unix/udp.c8
-rw-r--r--Utilities/cmlibuv/src/uv-data-getter-setters.c96
-rw-r--r--Utilities/cmlibuv/src/win/dl.c55
-rw-r--r--Utilities/cmlibuv/src/win/error.c2
-rw-r--r--Utilities/cmlibuv/src/win/fs.c581
-rw-r--r--Utilities/cmlibuv/src/win/getaddrinfo.c71
-rw-r--r--Utilities/cmlibuv/src/win/handle.c5
-rw-r--r--Utilities/cmlibuv/src/win/internal.h1
-rw-r--r--Utilities/cmlibuv/src/win/pipe.c137
-rw-r--r--Utilities/cmlibuv/src/win/process.c31
-rw-r--r--Utilities/cmlibuv/src/win/signal.c2
-rw-r--r--Utilities/cmlibuv/src/win/stream-inl.h3
-rw-r--r--Utilities/cmlibuv/src/win/tcp.c32
-rw-r--r--Utilities/cmlibuv/src/win/thread.c6
-rw-r--r--Utilities/cmlibuv/src/win/timer.c2
-rw-r--r--Utilities/cmlibuv/src/win/tty.c121
-rw-r--r--Utilities/cmlibuv/src/win/udp.c51
-rw-r--r--Utilities/cmlibuv/src/win/util.c11
-rw-r--r--Utilities/cmlibuv/src/win/winapi.c10
-rw-r--r--Utilities/cmlibuv/src/win/winapi.h26
-rw-r--r--Utilities/cmlibuv/src/win/winsock.c28
-rw-r--r--Utilities/cmlibuv/src/win/winsock.h3
202 files changed, 7505 insertions, 3677 deletions
diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst
index 1b0aa14..d4f644a 100644
--- a/Help/command/add_custom_command.rst
+++ b/Help/command/add_custom_command.rst
@@ -146,8 +146,10 @@ The options are:
Specify the primary input source file to the command. This is
treated just like any value given to the ``DEPENDS`` option
but also suggests to Visual Studio generators where to hang
- the custom command. At most one custom command may specify a
- given source file as its main dependency.
+ the custom command. Each source file may have at most one command
+ specifying it as its main dependency. A compile command (i.e. for a
+ library or an executable) counts as an implicit main dependency which
+ gets silently overwritten by a custom command specification.
``OUTPUT``
Specify the output files the command is expected to produce.
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
index dc5621a..0f6d4cf 100644
--- a/Help/manual/cmake-generator-expressions.7.rst
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -97,21 +97,35 @@ Available logical expressions are:
compile features and a list of supported compilers.
``$<COMPILE_LANGUAGE:lang>``
``1`` when the language used for compilation unit matches ``lang``,
- otherwise ``0``. This expression may be used to specify compile options for
- source files of a particular language in a target. For example, to specify
- the use of the ``-fno-exceptions`` compile option (compiler id checks
- elided):
+ otherwise ``0``. This expression may be used to specify compile options,
+ compile definitions, and include directories for source files of a
+ particular language in a target. For example:
.. code-block:: cmake
- add_executable(myapp main.cpp foo.c bar.cpp)
+ add_executable(myapp main.cpp foo.c bar.cpp zot.cu)
target_compile_options(myapp
PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
)
+ target_compile_definitions(myapp
+ PRIVATE $<$<COMPILE_LANGUAGE:CXX>:COMPILING_CXX>
+ $<$<COMPILE_LANGUAGE:CUDA>:COMPILING_CUDA>
+ )
+ target_include_directories(myapp
+ PRIVATE $<$<COMPILE_LANGUAGE:CXX>:/opt/foo/cxx_headers>
+ )
+
+ This specifies the use of the ``-fno-exceptions`` compile option,
+ ``COMPILING_CXX`` compile definition, and ``cxx_headers`` include
+ directory for C++ only (compiler id checks elided). It also specifies
+ a ``COMPILING_CUDA`` compile definition for CUDA.
- Note that with :ref:`Visual Studio Generators` there is no way to represent
+ Note that with :ref:`Visual Studio Generators` and :generator:`Xcode` there
+ is no way to represent target-wide compile definitions or include directories
+ separately for ``C`` and ``CXX`` languages.
+ Also, with :ref:`Visual Studio Generators` there is no way to represent
target-wide flags separately for ``C`` and ``CXX`` languages. Under these
- generators, target-wide flags for both C and C++ sources will be evaluated
+ generators, expressions for both C and C++ sources will be evaluated
using ``CXX`` if there are any C++ sources and otherwise using ``C``.
A workaround is to create separate libraries for each source file language
instead:
@@ -124,20 +138,6 @@ Available logical expressions are:
add_executable(myapp main.cpp)
target_link_libraries(myapp myapp_c myapp_cxx)
- The ``Makefile`` and ``Ninja`` based generators can also use this
- expression to specify compile-language specific compile definitions
- and include directories:
-
- .. code-block:: cmake
-
- add_executable(myapp main.cpp foo.c bar.cpp)
- target_compile_definitions(myapp
- PRIVATE $<$<COMPILE_LANGUAGE:CXX>:COMPILING_CXX>
- )
- target_include_directories(myapp
- PRIVATE $<$<COMPILE_LANGUAGE:CXX>:/opt/foo/cxx_headers>
- )
-
Informational Expressions
=========================
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index 2c63c4b..88b39d4 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -121,6 +121,7 @@ Properties on Targets
/prop_tgt/ARCHIVE_OUTPUT_NAME_CONFIG
/prop_tgt/ARCHIVE_OUTPUT_NAME
/prop_tgt/AUTOGEN_BUILD_DIR
+ /prop_tgt/AUTOGEN_PARALLEL
/prop_tgt/AUTOGEN_TARGET_DEPENDS
/prop_tgt/AUTOMOC_COMPILER_PREDEFINES
/prop_tgt/AUTOMOC_DEPEND_FILTERS
diff --git a/Help/manual/cmake-qt.7.rst b/Help/manual/cmake-qt.7.rst
index cafeae1..e5c593f 100644
--- a/Help/manual/cmake-qt.7.rst
+++ b/Help/manual/cmake-qt.7.rst
@@ -96,7 +96,8 @@ following targets by setting the :variable:`CMAKE_AUTOMOC` variable. The
options to pass to ``moc``. The :variable:`CMAKE_AUTOMOC_MOC_OPTIONS`
variable may be populated to pre-set the options for all following targets.
-Additional macro names to search for can be added to :prop_tgt:`AUTOMOC_MACRO_NAMES`.
+Additional macro names to search for can be added to
+:prop_tgt:`AUTOMOC_MACRO_NAMES`.
Additional ``moc`` dependency file names can be extracted from source code
by using :prop_tgt:`AUTOMOC_DEPEND_FILTERS`.
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 3f57612..c18d8da 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -276,6 +276,7 @@ Variables that Control the Build
/variable/CMAKE_ANDROID_STL_TYPE
/variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY
/variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY_CONFIG
+ /variable/CMAKE_AUTOGEN_PARALLEL
/variable/CMAKE_AUTOMOC
/variable/CMAKE_AUTOMOC_COMPILER_PREDEFINES
/variable/CMAKE_AUTOMOC_DEPEND_FILTERS
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index ff8c6c7..c2e6435 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -337,7 +337,7 @@ Available commands are:
``paxr`` (restricted pax, default), and ``zip``.
``time <command> [<args>...]``
- Run command and return elapsed time.
+ Run command and display elapsed time.
``touch <file>``
Touch a file.
diff --git a/Help/prop_tgt/AUTOGEN_PARALLEL.rst b/Help/prop_tgt/AUTOGEN_PARALLEL.rst
new file mode 100644
index 0000000..07fbc5a
--- /dev/null
+++ b/Help/prop_tgt/AUTOGEN_PARALLEL.rst
@@ -0,0 +1,21 @@
+AUTOGEN_PARALLEL
+----------------
+
+Number of parallel ``moc`` or ``uic`` processes to start when using
+:prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC`.
+
+The custom `<origin>_autogen` target starts a number of threads of which
+each one parses a source file and on demand starts a ``moc`` or ``uic``
+process. :prop_tgt:`AUTOGEN_PARALLEL` controls how many parallel threads
+(and therefore ``moc`` or ``uic`` processes) are started.
+
+- An empty (or unset) value or the string ``AUTO`` sets the number of
+ threads/processes to the number of physical CPUs on the host system.
+- A positive non zero integer value sets the exact thread/process count.
+- Otherwise a single thread/process is started.
+
+By default :prop_tgt:`AUTOGEN_PARALLEL` is initialized from
+:variable:`CMAKE_AUTOGEN_PARALLEL`.
+
+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 9e5261f..3bd693a 100644
--- a/Help/prop_tgt/AUTOMOC.rst
+++ b/Help/prop_tgt/AUTOMOC.rst
@@ -71,7 +71,8 @@ automoc targets together in an IDE, e.g. in MSVS.
The global property :prop_gbl:`AUTOGEN_SOURCE_GROUP` can be used to group
files generated by :prop_tgt:`AUTOMOC` together in an IDE, e.g. in MSVS.
-Additional macro names to search for can be added to :prop_tgt:`AUTOMOC_MACRO_NAMES`.
+Additional macro names to search for can be added to
+:prop_tgt:`AUTOMOC_MACRO_NAMES`.
Additional ``moc`` dependency file names can be extracted from source code
by using :prop_tgt:`AUTOMOC_DEPEND_FILTERS`.
@@ -82,5 +83,8 @@ which is controlled by :prop_tgt:`AUTOMOC_COMPILER_PREDEFINES`.
Source C++ files can be excluded from :prop_tgt:`AUTOMOC` processing by
enabling :prop_sf:`SKIP_AUTOMOC` or the broader :prop_sf:`SKIP_AUTOGEN`.
+The number of parallel ``moc`` processes to start can be modified by
+setting :prop_tgt:`AUTOGEN_PARALLEL`.
+
See the :manual:`cmake-qt(7)` manual for more information on using CMake
with Qt.
diff --git a/Help/prop_tgt/AUTOUIC.rst b/Help/prop_tgt/AUTOUIC.rst
index 1791384..4fc603f 100644
--- a/Help/prop_tgt/AUTOUIC.rst
+++ b/Help/prop_tgt/AUTOUIC.rst
@@ -33,5 +33,8 @@ autouic targets together in an IDE, e.g. in MSVS.
Source files can be excluded from :prop_tgt:`AUTOUIC` processing by
enabling :prop_sf:`SKIP_AUTOUIC` or the broader :prop_sf:`SKIP_AUTOGEN`.
+The number of parallel ``uic`` processes to start can be modified by
+setting :prop_tgt:`AUTOGEN_PARALLEL`.
+
See the :manual:`cmake-qt(7)` manual for more information on using CMake
with Qt.
diff --git a/Help/release/dev/CheckIncludeFile-required-libs.rst b/Help/release/dev/CheckIncludeFile-required-libs.rst
new file mode 100644
index 0000000..14c43d1
--- /dev/null
+++ b/Help/release/dev/CheckIncludeFile-required-libs.rst
@@ -0,0 +1,11 @@
+CheckIncludeFile-required-libs
+------------------------------
+
+* The :module:`CheckIncludeFile` module ``check_include_file`` macro
+ learned to honor the ``CMAKE_REQUIRED_LIBRARIES`` variable.
+
+* The :module:`CheckIncludeFileCXX` module ``check_include_file_cxx`` macro
+ learned to honor the ``CMAKE_REQUIRED_LIBRARIES`` variable.
+
+* The :module:`CheckIncludeFiles` module ``check_include_files`` macro
+ learned to honor the ``CMAKE_REQUIRED_LIBRARIES`` variable.
diff --git a/Help/release/dev/autogen-parallel.rst b/Help/release/dev/autogen-parallel.rst
new file mode 100644
index 0000000..50ae9a6
--- /dev/null
+++ b/Help/release/dev/autogen-parallel.rst
@@ -0,0 +1,10 @@
+autogen-parallel
+----------------
+
+* When using :prop_tgt:`AUTOMOC` or :prop_tgt:`AUTOUIC`, CMake starts multiple
+ parallel ``moc`` or ``uic`` processes to reduce the build time.
+ The new :variable:`CMAKE_AUTOGEN_PARALLEL` variable and
+ :prop_tgt:`AUTOGEN_PARALLEL` target property allow to modify the number of
+ parallel ``moc`` or ``uic`` processes to start.
+ By default CMake starts a single ``moc`` or ``uic`` process for each physical
+ CPU on the host system.
diff --git a/Help/release/dev/cache-newline.rst b/Help/release/dev/cache-newline.rst
new file mode 100644
index 0000000..96900bb
--- /dev/null
+++ b/Help/release/dev/cache-newline.rst
@@ -0,0 +1,7 @@
+cache-newline
+-------------
+
+* Variables containing newlines in their values now get truncated before the
+ newline when they are written to the cache file. In addition, a warning
+ comment is written to the cache file, and a warning message is displayed to
+ the user on the console.
diff --git a/Help/release/dev/extend-compile-language-genex.rst b/Help/release/dev/extend-compile-language-genex.rst
index 0a0a669..7c09376 100644
--- a/Help/release/dev/extend-compile-language-genex.rst
+++ b/Help/release/dev/extend-compile-language-genex.rst
@@ -1,7 +1,14 @@
extend-compile-language-genex
-----------------------------
-* The ``COMPILE_LANGUAGE`` :manual:`generator expression
- <cmake-generator-expressions(7)>` may now be used with
- :ref:`Visual Studio Generators` in :prop_tgt:`COMPILE_OPTIONS`
- and :command:`file(GENERATE)`.
+* :ref:`Visual Studio Generators` learned to support the ``COMPILE_LANGUAGE``
+ :manual:`generator expression <cmake-generator-expressions(7)>` in
+ target-wide :prop_tgt:`COMPILE_DEFINITIONS`,
+ :prop_tgt:`INCLUDE_DIRECTORIES`, :prop_tgt:`COMPILE_OPTIONS`, and
+ :command:`file(GENERATE)`.
+
+* The :generator:`Xcode` generator learned to support the ``COMPILE_LANGUAGE``
+ :manual:`generator expression <cmake-generator-expressions(7)>` in
+ target-wide :prop_tgt:`COMPILE_DEFINITIONS` and
+ :prop_tgt:`INCLUDE_DIRECTORIES`. It previously supported only
+ :prop_tgt:`COMPILE_OPTIONS` and :command:`file(GENERATE)`.
diff --git a/Help/variable/CMAKE_AUTOGEN_PARALLEL.rst b/Help/variable/CMAKE_AUTOGEN_PARALLEL.rst
new file mode 100644
index 0000000..dd9499a
--- /dev/null
+++ b/Help/variable/CMAKE_AUTOGEN_PARALLEL.rst
@@ -0,0 +1,10 @@
+CMAKE_AUTOGEN_PARALLEL
+----------------------
+
+Number of parallel ``moc`` or ``uic`` processes to start when using
+:prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC`.
+
+This variable is used to initialize the :prop_tgt:`AUTOGEN_PARALLEL` property
+on all the targets. See that target property for additional information.
+
+By default :variable:`CMAKE_AUTOGEN_PARALLEL` is unset.
diff --git a/Help/variable/CMAKE_AUTOMOC_MACRO_NAMES.rst b/Help/variable/CMAKE_AUTOMOC_MACRO_NAMES.rst
index 5b79c40..2c8997b 100644
--- a/Help/variable/CMAKE_AUTOMOC_MACRO_NAMES.rst
+++ b/Help/variable/CMAKE_AUTOMOC_MACRO_NAMES.rst
@@ -12,7 +12,7 @@ information.
The default value is ``Q_OBJECT;Q_GADGET;Q_NAMESPACE``.
Example
--------
+^^^^^^^
Let CMake know that source files that contain ``CUSTOM_MACRO`` must be ``moc``
processed as well::
diff --git a/Help/variable/CMAKE_CROSSCOMPILING.rst b/Help/variable/CMAKE_CROSSCOMPILING.rst
index cf9865b..9e96769 100644
--- a/Help/variable/CMAKE_CROSSCOMPILING.rst
+++ b/Help/variable/CMAKE_CROSSCOMPILING.rst
@@ -1,8 +1,26 @@
CMAKE_CROSSCOMPILING
--------------------
-Is CMake currently cross compiling.
+Intended to indicate whether CMake is cross compiling, but note limitations
+discussed below.
-This variable will be set to true by CMake if CMake is cross
-compiling. Specifically if the build platform is different from the
-target platform.
+This variable will be set to true by CMake if the :variable:`CMAKE_SYSTEM_NAME`
+variable has been set manually (i.e. in a toolchain file or as a cache entry
+from the :manual:`cmake <cmake(1)>` command line). In most cases, manually
+setting :variable:`CMAKE_SYSTEM_NAME` will only be done when cross compiling,
+since it will otherwise be given the same value as
+:variable:`CMAKE_HOST_SYSTEM_NAME` if not manually set, which is correct for
+the non-cross-compiling case. In the event that :variable:`CMAKE_SYSTEM_NAME`
+is manually set to the same value as :variable:`CMAKE_HOST_SYSTEM_NAME`, then
+``CMAKE_CROSSCOMPILING`` will still be set to true.
+
+Another case to be aware of is that builds targeting Apple platforms other than
+macOS are handled differently to other cross compiling scenarios. Rather than
+relying on :variable:`CMAKE_SYSTEM_NAME` to select the target platform, Apple
+device builds use :variable:`CMAKE_OSX_SYSROOT` to select the appropriate SDK,
+which indirectly determines the target platform. Furthermore, when using the
+Xcode generator, developers can switch between device and simulator builds at
+build time rather than having a single choice at configure time, so the concept
+of whether the build is cross compiling or not is more complex. Therefore, the
+use of ``CMAKE_CROSSCOMPILING`` is not recommended for projects targeting Apple
+devices.
diff --git a/Help/variable/CMAKE_LANG_COMPILER_EXTERNAL_TOOLCHAIN.rst b/Help/variable/CMAKE_LANG_COMPILER_EXTERNAL_TOOLCHAIN.rst
index 5be935b..cbe3544 100644
--- a/Help/variable/CMAKE_LANG_COMPILER_EXTERNAL_TOOLCHAIN.rst
+++ b/Help/variable/CMAKE_LANG_COMPILER_EXTERNAL_TOOLCHAIN.rst
@@ -6,7 +6,7 @@ The external toolchain for cross-compiling, if supported.
Some compiler toolchains do not ship their own auxiliary utilities such as
archivers and linkers. The compiler driver may support a command-line argument
to specify the location of such tools.
-``CMAKE_<LANG>_COMPILER_EXTERNAL_TOOLCHAIN`` may be set to a path to a path to
+``CMAKE_<LANG>_COMPILER_EXTERNAL_TOOLCHAIN`` may be set to a path to
the external toolchain and will be passed to the compiler driver if supported.
This variable may only be set in a toolchain file specified by
diff --git a/Modules/AutoRccInfo.cmake.in b/Modules/AutoRccInfo.cmake.in
index 5457a6f..cbab4a7 100644
--- a/Modules/AutoRccInfo.cmake.in
+++ b/Modules/AutoRccInfo.cmake.in
@@ -1,10 +1,6 @@
# Meta
set(ARCC_MULTI_CONFIG @_multi_config@)
# Directories and files
-set(ARCC_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@/")
-set(ARCC_CMAKE_SOURCE_DIR "@CMAKE_SOURCE_DIR@/")
-set(ARCC_CMAKE_CURRENT_SOURCE_DIR "@CMAKE_CURRENT_SOURCE_DIR@/")
-set(ARCC_CMAKE_CURRENT_BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@/")
set(ARCC_BUILD_DIR @_build_dir@)
# Qt environment
set(ARCC_RCC_EXECUTABLE @_qt_rcc_executable@)
diff --git a/Modules/AutogenInfo.cmake.in b/Modules/AutogenInfo.cmake.in
index 9a4a06d..7320c0a 100644
--- a/Modules/AutogenInfo.cmake.in
+++ b/Modules/AutogenInfo.cmake.in
@@ -1,5 +1,6 @@
# Meta
set(AM_MULTI_CONFIG @_multi_config@)
+set(AM_PARALLEL @_parallel@)
# Directories and files
set(AM_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@/")
set(AM_CMAKE_SOURCE_DIR "@CMAKE_SOURCE_DIR@/")
diff --git a/Modules/CheckIncludeFile.cmake b/Modules/CheckIncludeFile.cmake
index e5554c4..501fc9a 100644
--- a/Modules/CheckIncludeFile.cmake
+++ b/Modules/CheckIncludeFile.cmake
@@ -27,6 +27,8 @@
# list of macros to define (-DFOO=bar)
# ``CMAKE_REQUIRED_INCLUDES``
# list of include directories
+# ``CMAKE_REQUIRED_LIBRARIES``
+# list of libraries to link
# ``CMAKE_REQUIRED_QUIET``
# execute quietly without messages
#
@@ -59,6 +61,7 @@ macro(CHECK_INCLUDE_FILE INCLUDE VARIABLE)
${CMAKE_BINARY_DIR}
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckIncludeFile.c
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}
CMAKE_FLAGS
-DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_INCLUDE_FILE_FLAGS}
"${CHECK_INCLUDE_FILE_C_INCLUDE_DIRS}"
diff --git a/Modules/CheckIncludeFileCXX.cmake b/Modules/CheckIncludeFileCXX.cmake
index 7948bab..cdb25fb 100644
--- a/Modules/CheckIncludeFileCXX.cmake
+++ b/Modules/CheckIncludeFileCXX.cmake
@@ -27,6 +27,8 @@
# list of macros to define (-DFOO=bar)
# ``CMAKE_REQUIRED_INCLUDES``
# list of include directories
+# ``CMAKE_REQUIRED_LIBRARIES``
+# list of libraries to link
# ``CMAKE_REQUIRED_QUIET``
# execute quietly without messages
#
@@ -58,6 +60,7 @@ macro(CHECK_INCLUDE_FILE_CXX INCLUDE VARIABLE)
${CMAKE_BINARY_DIR}
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckIncludeFile.cxx
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}
CMAKE_FLAGS
-DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_INCLUDE_FILE_FLAGS}
"${CHECK_INCLUDE_FILE_CXX_INCLUDE_DIRS}"
diff --git a/Modules/CheckIncludeFiles.cmake b/Modules/CheckIncludeFiles.cmake
index 59afdab..14db68c 100644
--- a/Modules/CheckIncludeFiles.cmake
+++ b/Modules/CheckIncludeFiles.cmake
@@ -33,6 +33,8 @@
# list of macros to define (-DFOO=bar)
# ``CMAKE_REQUIRED_INCLUDES``
# list of include directories
+# ``CMAKE_REQUIRED_LIBRARIES``
+# list of libraries to link
# ``CMAKE_REQUIRED_QUIET``
# execute quietly without messages
#
@@ -102,6 +104,7 @@ macro(CHECK_INCLUDE_FILES INCLUDE VARIABLE)
${CMAKE_BINARY_DIR}
${src}
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}
CMAKE_FLAGS
-DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_INCLUDE_FILES_FLAGS}
"${CHECK_INCLUDE_FILES_INCLUDE_DIRS}"
diff --git a/Modules/FindDoxygen.cmake b/Modules/FindDoxygen.cmake
index 8aea4e0..599d799 100644
--- a/Modules/FindDoxygen.cmake
+++ b/Modules/FindDoxygen.cmake
@@ -411,6 +411,8 @@ macro(_Doxygen_find_doxygen)
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\doxygen_is1;Inno Setup: App Path]/bin"
/Applications/Doxygen.app/Contents/Resources
/Applications/Doxygen.app/Contents/MacOS
+ /Applications/Utilities/Doxygen.app/Contents/Resources
+ /Applications/Utilities/Doxygen.app/Contents/MacOS
DOC "Doxygen documentation generation tool (http://www.doxygen.org)"
)
mark_as_advanced(DOXYGEN_EXECUTABLE)
@@ -492,8 +494,11 @@ macro(_Doxygen_find_dot)
"C:/Program Files/ATT/Graphviz/bin"
[HKEY_LOCAL_MACHINE\\SOFTWARE\\ATT\\Graphviz;InstallPath]/bin
/Applications/Graphviz.app/Contents/MacOS
+ /Applications/Utilities/Graphviz.app/Contents/MacOS
/Applications/Doxygen.app/Contents/Resources
/Applications/Doxygen.app/Contents/MacOS
+ /Applications/Utilities/Doxygen.app/Contents/Resources
+ /Applications/Utilities/Doxygen.app/Contents/MacOS
DOC "Dot tool for use with Doxygen"
)
mark_as_advanced(DOXYGEN_DOT_EXECUTABLE)
diff --git a/Modules/FindJava.cmake b/Modules/FindJava.cmake
index b913e17..e3f5af6 100644
--- a/Modules/FindJava.cmake
+++ b/Modules/FindJava.cmake
@@ -237,10 +237,18 @@ if(Java_FIND_COMPONENTS)
endif()
elseif(component STREQUAL "Development")
list(APPEND _JAVA_REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAVAC_EXECUTABLE
- Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE)
- if(Java_JAVA_EXECUTABLE AND Java_JAVAC_EXECUTABLE
- AND Java_JAVAH_EXECUTABLE AND Java_JAVADOC_EXECUTABLE)
- set(Java_Development_FOUND TRUE)
+ Java_JAVADOC_EXECUTABLE)
+ if(Java_VERSION VERSION_LESS "1.10")
+ list(APPEND _JAVA_REQUIRED_VARS Java_JAVAH_EXECUTABLE)
+ if(Java_JAVA_EXECUTABLE AND Java_JAVAC_EXECUTABLE
+ AND Java_JAVAH_EXECUTABLE AND Java_JAVADOC_EXECUTABLE)
+ set(Java_Development_FOUND TRUE)
+ endif()
+ else()
+ if(Java_JAVA_EXECUTABLE AND Java_JAVAC_EXECUTABLE
+ AND Java_JAVADOC_EXECUTABLE)
+ set(Java_Development_FOUND TRUE)
+ endif()
endif()
elseif(component STREQUAL "IdlJ")
list(APPEND _JAVA_REQUIRED_VARS Java_IDLJ_EXECUTABLE)
@@ -268,11 +276,19 @@ if(Java_FIND_COMPONENTS)
endif()
else()
# Check for Development
- find_package_handle_standard_args(Java
- REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE
- Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE
- VERSION_VAR Java_VERSION_STRING
- )
+ if(Java_VERSION VERSION_LESS "1.10")
+ find_package_handle_standard_args(Java
+ REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE
+ Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE
+ VERSION_VAR Java_VERSION_STRING
+ )
+ else()
+ find_package_handle_standard_args(Java
+ REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE
+ Java_JAVADOC_EXECUTABLE
+ VERSION_VAR Java_VERSION_STRING
+ )
+ endif()
endif()
diff --git a/Modules/FindOpenGL.cmake b/Modules/FindOpenGL.cmake
index 9ccd46b..4d0786c 100644
--- a/Modules/FindOpenGL.cmake
+++ b/Modules/FindOpenGL.cmake
@@ -22,7 +22,6 @@
# Defined to the platform-specific OpenGL libraries if the system has OpenGL.
# ``OpenGL::OpenGL``
# Defined to libOpenGL if the system is GLVND-based.
-# ``OpenGL::GL``
# ``OpenGL::GLU``
# Defined if the system has GLU.
# ``OpenGL::GLX``
diff --git a/Modules/FindOpenMP.cmake b/Modules/FindOpenMP.cmake
index 893ddc6..ced092e 100644
--- a/Modules/FindOpenMP.cmake
+++ b/Modules/FindOpenMP.cmake
@@ -470,7 +470,7 @@ foreach(LANG IN LISTS OpenMP_FINDLIST)
if(OpenMP_${LANG}_FLAGS)
separate_arguments(_OpenMP_${LANG}_OPTIONS NATIVE_COMMAND "${OpenMP_${LANG}_FLAGS}")
set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
- INTERFACE_COMPILE_OPTIONS "${_OpenMP_${LANG}_OPTIONS}")
+ INTERFACE_COMPILE_OPTIONS "$<$<COMPILE_LANGUAGE:${LANG}>:${_OpenMP_${LANG}_OPTIONS}>")
unset(_OpenMP_${LANG}_OPTIONS)
endif()
if(OpenMP_${LANG}_LIBRARIES)
diff --git a/Modules/FindPythonInterp.cmake b/Modules/FindPythonInterp.cmake
index 64b98a8..3ef8e9f 100644
--- a/Modules/FindPythonInterp.cmake
+++ b/Modules/FindPythonInterp.cmake
@@ -100,6 +100,9 @@ if(NOT PYTHON_EXECUTABLE)
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-32\\InstallPath]
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-64\\InstallPath]
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-32\\InstallPath]
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-64\\InstallPath]
)
endforeach()
endif()
diff --git a/Modules/FindTCL.cmake b/Modules/FindTCL.cmake
index 80779b3..19eb932 100644
--- a/Modules/FindTCL.cmake
+++ b/Modules/FindTCL.cmake
@@ -116,7 +116,7 @@ find_library(TCL_LIBRARY
NAMES
tcl
tcl${TCL_LIBRARY_VERSION} tcl${TCL_TCLSH_VERSION} tcl${TK_WISH_VERSION}
- tcl86 tcl8.6
+ tcl86 tcl8.6 tcl86t tcl8.6t
tcl85 tcl8.5
tcl84 tcl8.4
tcl83 tcl8.3
@@ -130,7 +130,7 @@ find_library(TK_LIBRARY
NAMES
tk
tk${TK_LIBRARY_VERSION} tk${TCL_TCLSH_VERSION} tk${TK_WISH_VERSION}
- tk86 tk8.6
+ tk86 tk8.6 tk86t tk8.6t
tk85 tk8.5
tk84 tk8.4
tk83 tk8.3
diff --git a/Modules/Platform/AIX-GNU.cmake b/Modules/Platform/AIX-GNU.cmake
index 7f08c4a..0abbb61 100644
--- a/Modules/Platform/AIX-GNU.cmake
+++ b/Modules/Platform/AIX-GNU.cmake
@@ -24,5 +24,7 @@ macro(__aix_compiler_gnu lang)
set(CMAKE_${lang}_USE_IMPLICIT_LINK_DIRECTORIES_IN_RUNTIME_PATH 1)
set(CMAKE_${lang}_LINK_FLAGS "-Wl,-bnoipath")
- unset(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY)
+ if(CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 7 OR CMAKE_SYSTEM_VERSION VERSION_LESS 7.1)
+ unset(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY)
+ endif()
endmacro()
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 1b46377..cd1287c 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -313,8 +313,8 @@ set(SRCS
cmQtAutoGen.h
cmQtAutoGenerator.cxx
cmQtAutoGenerator.h
- cmQtAutoGeneratorInitializer.cxx
- cmQtAutoGeneratorInitializer.h
+ cmQtAutoGenInitializer.cxx
+ cmQtAutoGenInitializer.h
cmQtAutoGeneratorMocUic.cxx
cmQtAutoGeneratorMocUic.h
cmQtAutoGeneratorRcc.cxx
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 76fd7c4..b41f400 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 10)
-set(CMake_VERSION_PATCH 20180114)
+set(CMake_VERSION_PATCH 20180122)
#set(CMake_VERSION_RC 1)
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
index c8806a7..e332a77 100644
--- a/Source/CTest/cmProcess.cxx
+++ b/Source/CTest/cmProcess.cxx
@@ -5,19 +5,19 @@
#include "cmCTest.h"
#include "cmCTestRunTest.h"
#include "cmCTestTestHandler.h"
-#include "cmProcessOutput.h"
#include "cmsys/Process.h"
#include <algorithm>
#include <fcntl.h>
#include <iostream>
#include <signal.h>
-#include <stdint.h>
#include <string>
#if !defined(_WIN32)
#include <unistd.h>
#endif
+#define CM_PROCESS_BUF_SIZE 65536
+
#if defined(_WIN32) && !defined(__CYGWIN__)
#include <io.h>
@@ -60,6 +60,7 @@ static int cmProcessGetPipes(int* fds)
cmProcess::cmProcess(cmCTestRunTest& runner)
: Runner(runner)
+ , Conv(cmProcessOutput::UTF8, CM_PROCESS_BUF_SIZE)
{
this->Timeout = std::chrono::duration<double>::zero();
this->TotalTime = std::chrono::duration<double>::zero();
@@ -232,9 +233,7 @@ void cmProcess::OnRead(ssize_t nread, const uv_buf_t* buf)
std::string line;
if (nread > 0) {
std::string strdata;
- cmProcessOutput processOutput(cmProcessOutput::UTF8,
- static_cast<unsigned int>(buf->len));
- processOutput.DecodeText(buf->base, static_cast<size_t>(nread), strdata);
+ this->Conv.DecodeText(buf->base, static_cast<size_t>(nread), strdata);
this->Output.insert(this->Output.end(), strdata.begin(), strdata.end());
while (this->Output.GetLine(line)) {
@@ -245,6 +244,10 @@ void cmProcess::OnRead(ssize_t nread, const uv_buf_t* buf)
return;
}
+ if (nread == 0) {
+ return;
+ }
+
// The process will provide no more data.
if (nread != UV_EOF) {
auto error = static_cast<int>(nread);
@@ -258,6 +261,7 @@ void cmProcess::OnRead(ssize_t nread, const uv_buf_t* buf)
}
this->ReadHandleClosed = true;
+ this->PipeReader.reset();
if (this->ProcessHandleClosed) {
uv_timer_stop(this->Timer);
this->Runner.FinalizeTest();
@@ -271,10 +275,10 @@ void cmProcess::OnAllocateCB(uv_handle_t* handle, size_t suggested_size,
self->OnAllocate(suggested_size, buf);
}
-void cmProcess::OnAllocate(size_t suggested_size, uv_buf_t* buf)
+void cmProcess::OnAllocate(size_t /*suggested_size*/, uv_buf_t* buf)
{
- if (this->Buf.size() < suggested_size) {
- this->Buf.resize(suggested_size);
+ if (this->Buf.size() != CM_PROCESS_BUF_SIZE) {
+ this->Buf.resize(CM_PROCESS_BUF_SIZE);
}
*buf =
diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h
index 9250896..633be24 100644
--- a/Source/CTest/cmProcess.h
+++ b/Source/CTest/cmProcess.h
@@ -5,13 +5,14 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include "cmProcessOutput.h"
#include "cmUVHandlePtr.h"
#include "cm_uv.h"
#include <chrono>
#include <stddef.h>
+#include <stdint.h>
#include <string>
-#include <sys/types.h>
#include <vector>
class cmCTestRunTest;
@@ -80,6 +81,7 @@ private:
std::vector<char> Buf;
cmCTestRunTest& Runner;
+ cmProcessOutput Conv;
int Signal = 0;
cmProcess::State ProcessState = cmProcess::State::Starting;
diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx
index 44095ec..64aa46e 100644
--- a/Source/cmCacheManager.cxx
+++ b/Source/cmCacheManager.cxx
@@ -10,6 +10,7 @@
#include <string.h>
#include "cmGeneratedFileStream.h"
+#include "cmMessenger.h"
#include "cmState.h"
#include "cmSystemTools.h"
#include "cmVersion.h"
@@ -205,7 +206,8 @@ bool cmCacheManager::ReadPropertyEntry(std::string const& entryKey,
return false;
}
-void cmCacheManager::WritePropertyEntries(std::ostream& os, CacheIterator i)
+void cmCacheManager::WritePropertyEntries(std::ostream& os, CacheIterator i,
+ cmMessenger* messenger)
{
for (const char** p = this->PersistentProperties; *p; ++p) {
if (const char* value = i.GetProperty(*p)) {
@@ -221,11 +223,13 @@ void cmCacheManager::WritePropertyEntries(std::ostream& os, CacheIterator i)
os << ":INTERNAL=";
this->OutputValue(os, value);
os << "\n";
+ cmCacheManager::OutputNewlineTruncationWarning(os, key, value,
+ messenger);
}
}
}
-bool cmCacheManager::SaveCache(const std::string& path)
+bool cmCacheManager::SaveCache(const std::string& path, cmMessenger* messenger)
{
std::string cacheFile = path;
cacheFile += "/CMakeCache.txt";
@@ -316,7 +320,10 @@ bool cmCacheManager::SaveCache(const std::string& path)
this->OutputKey(fout, i.first);
fout << ":" << cmState::CacheEntryTypeToString(t) << "=";
this->OutputValue(fout, ce.Value);
- fout << "\n\n";
+ fout << "\n";
+ cmCacheManager::OutputNewlineTruncationWarning(fout, i.first, ce.Value,
+ messenger);
+ fout << "\n";
}
}
@@ -333,7 +340,7 @@ bool cmCacheManager::SaveCache(const std::string& path)
}
cmStateEnums::CacheEntryType t = i.GetType();
- this->WritePropertyEntries(fout, i);
+ this->WritePropertyEntries(fout, i, messenger);
if (t == cmStateEnums::INTERNAL) {
// Format is key:type=value
if (const char* help = i.GetProperty("HELPSTRING")) {
@@ -343,6 +350,8 @@ bool cmCacheManager::SaveCache(const std::string& path)
fout << ":" << cmState::CacheEntryTypeToString(t) << "=";
this->OutputValue(fout, i.GetValue());
fout << "\n";
+ cmCacheManager::OutputNewlineTruncationWarning(fout, i.GetName(),
+ i.GetValue(), messenger);
}
}
fout << "\n";
@@ -390,6 +399,19 @@ void cmCacheManager::OutputKey(std::ostream& fout, std::string const& key)
void cmCacheManager::OutputValue(std::ostream& fout, std::string const& value)
{
+ // look for and truncate newlines
+ std::string::size_type newline = value.find('\n');
+ if (newline != std::string::npos) {
+ std::string truncated = value.substr(0, newline);
+ OutputValueNoNewlines(fout, truncated);
+ } else {
+ OutputValueNoNewlines(fout, value);
+ }
+}
+
+void cmCacheManager::OutputValueNoNewlines(std::ostream& fout,
+ std::string const& value)
+{
// if value has trailing space or tab, enclose it in single quotes
if (!value.empty() &&
(value[value.size() - 1] == ' ' || value[value.size() - 1] == '\t')) {
@@ -423,6 +445,50 @@ void cmCacheManager::OutputHelpString(std::ostream& fout,
}
}
+void cmCacheManager::OutputWarningComment(std::ostream& fout,
+ std::string const& message,
+ bool wrapSpaces)
+{
+ std::string::size_type end = message.size();
+ std::string oneLine;
+ std::string::size_type pos = 0;
+ for (std::string::size_type i = 0; i <= end; i++) {
+ if ((i == end) || (message[i] == '\n') ||
+ ((i - pos >= 60) && (message[i] == ' ') && wrapSpaces)) {
+ fout << "# ";
+ if (message[pos] == '\n') {
+ pos++;
+ fout << "\\n";
+ }
+ oneLine = message.substr(pos, i - pos);
+ fout << oneLine << "\n";
+ pos = i;
+ }
+ }
+}
+
+void cmCacheManager::OutputNewlineTruncationWarning(std::ostream& fout,
+ std::string const& key,
+ std::string const& value,
+ cmMessenger* messenger)
+{
+ if (value.find('\n') != std::string::npos) {
+ if (messenger) {
+ std::string message = "Value of ";
+ message += key;
+ message += " contained a newline; truncating";
+ messenger->IssueMessage(cmake::WARNING, message);
+ }
+
+ std::string comment = "WARNING: Value of ";
+ comment += key;
+ comment += " contained a newline and was truncated. Original value:";
+
+ OutputWarningComment(fout, comment, true);
+ OutputWarningComment(fout, value, false);
+ }
+}
+
void cmCacheManager::RemoveCacheEntry(const std::string& key)
{
CacheEntryMap::iterator i = this->Cache.find(key);
diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h
index 28cba85..73923d1 100644
--- a/Source/cmCacheManager.h
+++ b/Source/cmCacheManager.h
@@ -15,7 +15,7 @@
#include "cmPropertyMap.h"
#include "cmStateTypes.h"
-class cmake;
+class cmMessenger;
/** \class cmCacheManager
* \brief Control class for cmake's cache
@@ -108,7 +108,7 @@ public:
std::set<std::string>& includes);
///! Save cache for given makefile. Saves to output path/CMakeCache.txt
- bool SaveCache(const std::string& path);
+ bool SaveCache(const std::string& path, cmMessenger* messenger);
///! Delete the cache given
bool DeleteCache(const std::string& path);
@@ -218,16 +218,25 @@ protected:
unsigned int CacheMinorVersion;
private:
- cmake* CMakeInstance;
typedef std::map<std::string, CacheEntry> CacheEntryMap;
static void OutputHelpString(std::ostream& fout,
const std::string& helpString);
+ static void OutputWarningComment(std::ostream& fout,
+ std::string const& message,
+ bool wrapSpaces);
+ static void OutputNewlineTruncationWarning(std::ostream& fout,
+ std::string const& key,
+ std::string const& value,
+ cmMessenger* messenger);
static void OutputKey(std::ostream& fout, std::string const& key);
static void OutputValue(std::ostream& fout, std::string const& value);
+ static void OutputValueNoNewlines(std::ostream& fout,
+ std::string const& value);
static const char* PersistentProperties[];
bool ReadPropertyEntry(std::string const& key, CacheEntry& e);
- void WritePropertyEntries(std::ostream& os, CacheIterator i);
+ void WritePropertyEntries(std::ostream& os, CacheIterator i,
+ cmMessenger* messenger);
CacheEntryMap Cache;
// Only cmake and cmState should be able to add cache values
diff --git a/Source/cmGeneratorExpressionEvaluationFile.cxx b/Source/cmGeneratorExpressionEvaluationFile.cxx
index 87b6b34..c988969 100644
--- a/Source/cmGeneratorExpressionEvaluationFile.cxx
+++ b/Source/cmGeneratorExpressionEvaluationFile.cxx
@@ -13,6 +13,7 @@
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmSourceFile.h"
+#include "cmSourceFileLocationKind.h"
#include "cmSystemTools.h"
#include "cmake.h"
@@ -102,7 +103,8 @@ void cmGeneratorExpressionEvaluationFile::CreateOutputFile(
for (std::string const& le : enabledLanguages) {
std::string name = this->OutputFileExpr->Evaluate(
lg, config, false, nullptr, nullptr, nullptr, le);
- cmSourceFile* sf = lg->GetMakefile()->GetOrCreateSource(name);
+ cmSourceFile* sf = lg->GetMakefile()->GetOrCreateSource(
+ name, false, cmSourceFileLocationKind::Known);
sf->SetProperty("GENERATED", "1");
gg->SetFilenameTargetDepends(
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 3d311d6..34ef45f 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -805,7 +805,7 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode
const std::vector<std::string>& parameters,
cmGeneratorExpressionContext* context,
const GeneratorExpressionContent* content,
- cmGeneratorExpressionDAGChecker* dagChecker) const override
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
if (context->Language.empty()) {
reportError(
@@ -827,33 +827,14 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode
return std::string();
}
std::string genName = gg->GetName();
- if (genName.find("Visual Studio") != std::string::npos) {
- if (dagChecker && (dagChecker->EvaluatingCompileDefinitions() ||
- dagChecker->EvaluatingIncludeDirectories())) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS "
- "and file(GENERATE) with the Visual Studio generator.");
- return std::string();
- }
- } else if (genName.find("Xcode") != std::string::npos) {
- if (dagChecker && (dagChecker->EvaluatingCompileDefinitions() ||
- dagChecker->EvaluatingIncludeDirectories())) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS "
- "and file(GENERATE) with the Xcode generator.");
- return std::string();
- }
- } else {
- if (genName.find("Makefiles") == std::string::npos &&
- genName.find("Ninja") == std::string::npos &&
- genName.find("Watcom WMake") == std::string::npos) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<COMPILE_LANGUAGE:...> not supported for this generator.");
- return std::string();
- }
+ if (genName.find("Makefiles") == std::string::npos &&
+ genName.find("Ninja") == std::string::npos &&
+ genName.find("Visual Studio") == std::string::npos &&
+ genName.find("Xcode") == std::string::npos &&
+ genName.find("Watcom WMake") == std::string::npos) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<COMPILE_LANGUAGE:...> not supported for this generator.");
+ return std::string();
}
if (parameters.empty()) {
return context->Language;
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index fd9b488..47a9390 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -33,7 +33,7 @@
#include "cmMakefile.h"
#include "cmOutputConverter.h"
#include "cmPolicies.h"
-#include "cmQtAutoGeneratorInitializer.h"
+#include "cmQtAutoGenInitializer.h"
#include "cmSourceFile.h"
#include "cmState.h"
#include "cmStateDirectory.h"
@@ -1473,10 +1473,10 @@ bool cmGlobalGenerator::ComputeTargetDepends()
return true;
}
-std::vector<std::unique_ptr<cmQtAutoGeneratorInitializer>>
+std::vector<std::unique_ptr<cmQtAutoGenInitializer>>
cmGlobalGenerator::CreateQtAutoGenInitializers()
{
- std::vector<std::unique_ptr<cmQtAutoGeneratorInitializer>> autogenInits;
+ std::vector<std::unique_ptr<cmQtAutoGenInitializer>> autogenInits;
#ifdef CMAKE_BUILD_WITH_CMAKE
for (cmLocalGenerator* localGen : this->LocalGenerators) {
@@ -1506,13 +1506,13 @@ cmGlobalGenerator::CreateQtAutoGenInitializers()
}
std::string qtVersionMajor =
- cmQtAutoGeneratorInitializer::GetQtMajorVersion(target);
+ cmQtAutoGenInitializer::GetQtMajorVersion(target);
// don't do anything if there is no Qt4 or Qt5Core (which contains moc)
if (qtVersionMajor != "4" && qtVersionMajor != "5") {
continue;
}
- autogenInits.emplace_back(new cmQtAutoGeneratorInitializer(
+ autogenInits.emplace_back(new cmQtAutoGenInitializer(
target, mocEnabled, uicEnabled, rccEnabled, qtVersionMajor));
}
}
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 92e6a29..3ebff82 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -32,7 +32,7 @@ class cmLinkLineComputer;
class cmLocalGenerator;
class cmMakefile;
class cmOutputConverter;
-class cmQtAutoGeneratorInitializer;
+class cmQtAutoGenInitializer;
class cmSourceFile;
class cmStateDirectory;
class cmake;
@@ -437,7 +437,7 @@ protected:
virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const;
// Qt auto generators
- std::vector<std::unique_ptr<cmQtAutoGeneratorInitializer>>
+ std::vector<std::unique_ptr<cmQtAutoGenInitializer>>
CreateQtAutoGenInitializers();
std::string SelectMakeProgram(const std::string& makeProgram,
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 338c2b4..bd51f60 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -1703,6 +1703,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
gtgt->GetName().c_str());
return;
}
+ std::string const& langForPreprocessor = llang;
if (gtgt->IsIPOEnabled(llang, configName)) {
const char* ltoValue =
@@ -1723,7 +1724,10 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
this->AppendDefines(ppDefs, exportMacro);
}
std::vector<std::string> targetDefines;
- gtgt->GetCompileDefinitions(targetDefines, configName, "C");
+ if (!langForPreprocessor.empty()) {
+ gtgt->GetCompileDefinitions(targetDefines, configName,
+ langForPreprocessor);
+ }
this->AppendDefines(ppDefs, targetDefines);
buildSettings->AddAttribute("GCC_PREPROCESSOR_DEFINITIONS",
ppDefs.CreateList());
@@ -1996,8 +2000,10 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
const bool emitSystemIncludes = this->XcodeVersion >= 83;
std::vector<std::string> includes;
- this->CurrentLocalGenerator->GetIncludeDirectories(includes, gtgt, "C",
- configName);
+ if (!langForPreprocessor.empty()) {
+ this->CurrentLocalGenerator->GetIncludeDirectories(
+ includes, gtgt, langForPreprocessor, configName);
+ }
std::set<std::string> emitted;
emitted.insert("/System/Library/Frameworks");
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index eccd4d0..59c20a9 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -637,7 +637,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
configType = projectType;
}
std::string flags;
- if (strcmp(configType, "10") != 0) {
+ std::string langForClCompile;
+ if (target->GetType() <= cmStateEnums::OBJECT_LIBRARY) {
const std::string& linkLanguage =
(this->FortranProject ? std::string("Fortran")
: target->GetLinkerLanguage(configName));
@@ -647,10 +648,11 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
target->GetName().c_str());
return;
}
- if (linkLanguage == "C" || linkLanguage == "CXX" ||
- linkLanguage == "Fortran") {
+ langForClCompile = linkLanguage;
+ if (langForClCompile == "C" || langForClCompile == "CXX" ||
+ langForClCompile == "Fortran") {
std::string baseFlagVar = "CMAKE_";
- baseFlagVar += linkLanguage;
+ baseFlagVar += langForClCompile;
baseFlagVar += "_FLAGS";
flags = this->Makefile->GetRequiredDefinition(baseFlagVar.c_str());
std::string flagVar =
@@ -667,7 +669,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
}
// Add the target-specific flags.
- this->AddCompileOptions(flags, target, linkLanguage, configName);
+ this->AddCompileOptions(flags, target, langForClCompile, configName);
// Check IPO related warning/error.
target->IsIPOEnabled(linkLanguage, configName);
@@ -703,7 +705,9 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
targetOptions.Parse(defineFlags.c_str());
targetOptions.ParseFinish();
std::vector<std::string> targetDefines;
- target->GetCompileDefinitions(targetDefines, configName, "CXX");
+ if (!langForClCompile.empty()) {
+ target->GetCompileDefinitions(targetDefines, configName, langForClCompile);
+ }
targetOptions.AddDefines(targetDefines);
targetOptions.SetVerboseMakefile(
this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
@@ -792,10 +796,13 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
<< "\\$(ConfigurationName)\"\n";
}
fout << "\t\t\t\tAdditionalIncludeDirectories=\"";
- std::vector<std::string> includes;
- this->GetIncludeDirectories(includes, target, "C", configName);
- std::vector<std::string>::iterator i = includes.begin();
- for (; i != includes.end(); ++i) {
+ std::vector<std::string> includes_cl;
+ if (!langForClCompile.empty()) {
+ this->GetIncludeDirectories(includes_cl, target, langForClCompile,
+ configName);
+ }
+ std::vector<std::string>::iterator i = includes_cl.begin();
+ for (; i != includes_cl.end(); ++i) {
// output the include path
std::string ipath = this->ConvertToXMLOutputPath(i->c_str());
fout << ipath << ";";
@@ -810,7 +817,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
}
fout << "\"\n";
targetOptions.OutputFlagMap(fout, "\t\t\t\t");
- targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n", "CXX");
+ targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n",
+ langForClCompile);
fout << "\t\t\t\tObjectFile=\"$(IntDir)\\\"\n";
if (target->GetType() <= cmStateEnums::OBJECT_LIBRARY) {
// Specify the compiler program database file if configured.
@@ -829,9 +837,12 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
"\t\t\t\tName=\"MASM\"\n"
"\t\t\t\tIncludePaths=\""
;
+ std::vector<std::string> includes_masm;
+ this->GetIncludeDirectories(includes_masm, target, "ASM_MASM",
+ configName);
/* clang-format on */
const char* sep = "";
- for (i = includes.begin(); i != includes.end(); ++i) {
+ for (i = includes_masm.begin(); i != includes_masm.end(); ++i) {
std::string inc = *i;
cmConvertToWindowsSlash(inc);
fout << sep << this->EscapeForXML(inc);
@@ -859,7 +870,9 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
}
fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n"
<< "\t\t\t\tAdditionalIncludeDirectories=\"";
- for (i = includes.begin(); i != includes.end(); ++i) {
+ std::vector<std::string> includes_rc;
+ this->GetIncludeDirectories(includes_rc, target, "RC", configName);
+ for (i = includes_rc.begin(); i != includes_rc.end(); ++i) {
std::string ipath = this->ConvertToXMLOutputPath(i->c_str());
fout << ipath << ";";
}
@@ -873,7 +886,9 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
}
fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n";
fout << "\t\t\t\tAdditionalIncludeDirectories=\"";
- for (i = includes.begin(); i != includes.end(); ++i) {
+ std::vector<std::string> includes_midl;
+ this->GetIncludeDirectories(includes_midl, target, "MIDL", configName);
+ for (i = includes_midl.begin(); i != includes_midl.end(); ++i) {
std::string ipath = this->ConvertToXMLOutputPath(i->c_str());
fout << ipath << ";";
}
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index b42495c..eeeb54f 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -1965,7 +1965,7 @@ cmSourceGroup* cmMakefile::GetSourceGroup(
if (sg != nullptr) {
// iterate through its children to find match source group
for (unsigned int i = 1; i < name.size(); ++i) {
- sg = sg->LookupChild(name[i].c_str());
+ sg = sg->LookupChild(name[i]);
if (sg == nullptr) {
break;
}
@@ -2009,7 +2009,7 @@ void cmMakefile::AddSourceGroup(const std::vector<std::string>& name,
if (i == -1) {
// group does not exist nor belong to any existing group
// add its first component
- this->SourceGroups.push_back(cmSourceGroup(name[0].c_str(), regex));
+ this->SourceGroups.push_back(cmSourceGroup(name[0], regex));
sg = this->GetSourceGroup(currentName);
i = 0; // last component found
}
@@ -2019,9 +2019,8 @@ void cmMakefile::AddSourceGroup(const std::vector<std::string>& name,
}
// build the whole source group path
for (++i; i <= lastElement; ++i) {
- sg->AddChild(
- cmSourceGroup(name[i].c_str(), nullptr, sg->GetFullName().c_str()));
- sg = sg->LookupChild(name[i].c_str());
+ sg->AddChild(cmSourceGroup(name[i], nullptr, sg->GetFullName().c_str()));
+ sg = sg->LookupChild(name[i]);
}
sg->SetGroupRegex(regex);
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index e0cc35a..594e0f5 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -760,7 +760,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
/*implicitOuts=*/cmNinjaDeps(), explicitDeps,
implicitDeps, orderOnlyDeps, vars, rspfile,
commandLineLengthLimit, &usedResponseFile);
- this->WriteDeviceLinkRule(usedResponseFile);
+ this->WriteDeviceLinkRule(false);
}
void cmNinjaNormalTargetGenerator::WriteLinkStatement()
diff --git a/Source/cmQtAutoGen.cxx b/Source/cmQtAutoGen.cxx
index 255a532..18ecbe7 100644
--- a/Source/cmQtAutoGen.cxx
+++ b/Source/cmQtAutoGen.cxx
@@ -2,16 +2,13 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmQtAutoGen.h"
#include "cmAlgorithms.h"
-#include "cmProcessOutput.h"
#include "cmSystemTools.h"
-#include "cmsys/FStream.hxx"
#include "cmsys/RegularExpression.hxx"
#include <algorithm>
#include <iterator>
#include <sstream>
-#include <stddef.h>
// - Static variables
@@ -21,8 +18,8 @@ std::string const genNameUic = "AutoUic";
std::string const genNameRcc = "AutoRcc";
std::string const mcNameSingle = "SINGLE";
-std::string const mcNameWrap = "WRAP";
-std::string const mcNameFull = "FULL";
+std::string const mcNameWrapper = "WRAPPER";
+std::string const mcNameMulti = "MULTI";
// - Static functions
@@ -80,203 +77,53 @@ void MergeOptions(std::vector<std::string>& baseOpts,
baseOpts.insert(baseOpts.end(), extraOpts.begin(), extraOpts.end());
}
-/// @brief Reads the resource files list from from a .qrc file - Qt4 version
-/// @return True if the .qrc file was successfully parsed
-static bool RccListInputsQt4(std::string const& fileName,
- std::vector<std::string>& files,
- std::string* errorMessage)
-{
- bool allGood = true;
- // Read qrc file content into string
- std::string qrcContents;
- {
- cmsys::ifstream ifs(fileName.c_str());
- if (ifs) {
- std::ostringstream osst;
- osst << ifs.rdbuf();
- qrcContents = osst.str();
- } else {
- if (errorMessage != nullptr) {
- std::string& err = *errorMessage;
- err = "rcc file not readable:\n ";
- err += cmQtAutoGen::Quoted(fileName);
- err += "\n";
- }
- allGood = false;
- }
- }
- if (allGood) {
- // qrc file directory
- std::string qrcDir(cmSystemTools::GetFilenamePath(fileName));
- if (!qrcDir.empty()) {
- qrcDir += '/';
- }
-
- cmsys::RegularExpression fileMatchRegex("(<file[^<]+)");
- cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)");
-
- size_t offset = 0;
- while (fileMatchRegex.find(qrcContents.c_str() + offset)) {
- std::string qrcEntry = fileMatchRegex.match(1);
- offset += qrcEntry.size();
- {
- fileReplaceRegex.find(qrcEntry);
- std::string tag = fileReplaceRegex.match(1);
- qrcEntry = qrcEntry.substr(tag.size());
- }
- if (!cmSystemTools::FileIsFullPath(qrcEntry.c_str())) {
- qrcEntry = qrcDir + qrcEntry;
- }
- files.push_back(qrcEntry);
- }
- }
- return allGood;
-}
-
-/// @brief Reads the resource files list from from a .qrc file - Qt5 version
-/// @return True if the .qrc file was successfully parsed
-static bool RccListInputsQt5(std::string const& rccCommand,
- std::vector<std::string> const& rccListOptions,
- std::string const& fileName,
- std::vector<std::string>& files,
- std::string* errorMessage)
-{
- if (rccCommand.empty()) {
- cmSystemTools::Error("rcc executable not available");
- return false;
- }
-
- std::string const fileDir = cmSystemTools::GetFilenamePath(fileName);
- std::string const fileNameName = cmSystemTools::GetFilenameName(fileName);
-
- // Run rcc list command
- bool result = false;
- int retVal = 0;
- std::string rccStdOut;
- std::string rccStdErr;
- {
- std::vector<std::string> command;
- command.push_back(rccCommand);
- command.insert(command.end(), rccListOptions.begin(),
- rccListOptions.end());
- command.push_back(fileNameName);
- result = cmSystemTools::RunSingleCommand(
- command, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(),
- cmSystemTools::OUTPUT_NONE, 0.0, cmProcessOutput::Auto);
- }
- if (!result || retVal) {
- if (errorMessage != nullptr) {
- std::string& err = *errorMessage;
- err = "rcc list process failed for:\n ";
- err += cmQtAutoGen::Quoted(fileName);
- err += "\n";
- err += rccStdOut;
- err += "\n";
- err += rccStdErr;
- err += "\n";
- }
- return false;
- }
-
- // Lambda to strip CR characters
- auto StripCR = [](std::string& line) {
- std::string::size_type cr = line.find('\r');
- if (cr != std::string::npos) {
- line = line.substr(0, cr);
- }
- };
-
- // Parse rcc std output
- {
- std::istringstream ostr(rccStdOut);
- std::string oline;
- while (std::getline(ostr, oline)) {
- StripCR(oline);
- if (!oline.empty()) {
- files.push_back(oline);
- }
- }
- }
- // Parse rcc error output
- {
- std::istringstream estr(rccStdErr);
- std::string eline;
- while (std::getline(estr, eline)) {
- StripCR(eline);
- if (cmHasLiteralPrefix(eline, "RCC: Error in")) {
- static std::string searchString = "Cannot find file '";
-
- std::string::size_type pos = eline.find(searchString);
- if (pos == std::string::npos) {
- if (errorMessage != nullptr) {
- std::string& err = *errorMessage;
- err = "rcc lists unparsable output:\n";
- err += cmQtAutoGen::Quoted(eline);
- err += "\n";
- }
- return false;
- }
- pos += searchString.length();
- std::string::size_type sz = eline.size() - pos - 1;
- files.push_back(eline.substr(pos, sz));
- }
- }
- }
-
- // Convert relative paths to absolute paths
- for (std::string& resFile : files) {
- resFile = cmSystemTools::CollapseCombinedPath(fileDir, resFile);
- }
-
- return true;
-}
-
// - Class definitions
-std::string const cmQtAutoGen::listSep = "<<<S>>>";
+std::string const cmQtAutoGen::ListSep = "<<<S>>>";
+unsigned int const cmQtAutoGen::ParallelMax = 64;
-std::string const& cmQtAutoGen::GeneratorName(Generator type)
+std::string const& cmQtAutoGen::GeneratorName(GeneratorT type)
{
switch (type) {
- case Generator::GEN:
+ case GeneratorT::GEN:
return genNameGen;
- case Generator::MOC:
+ case GeneratorT::MOC:
return genNameMoc;
- case Generator::UIC:
+ case GeneratorT::UIC:
return genNameUic;
- case Generator::RCC:
+ case GeneratorT::RCC:
return genNameRcc;
}
return genNameGen;
}
-std::string cmQtAutoGen::GeneratorNameUpper(Generator genType)
+std::string cmQtAutoGen::GeneratorNameUpper(GeneratorT genType)
{
return cmSystemTools::UpperCase(cmQtAutoGen::GeneratorName(genType));
}
-std::string const& cmQtAutoGen::MultiConfigName(MultiConfig config)
+std::string const& cmQtAutoGen::MultiConfigName(MultiConfigT config)
{
switch (config) {
- case MultiConfig::SINGLE:
+ case MultiConfigT::SINGLE:
return mcNameSingle;
- case MultiConfig::WRAP:
- return mcNameWrap;
- case MultiConfig::FULL:
- return mcNameFull;
+ case MultiConfigT::WRAPPER:
+ return mcNameWrapper;
+ case MultiConfigT::MULTI:
+ return mcNameMulti;
}
- return mcNameWrap;
+ return mcNameWrapper;
}
-cmQtAutoGen::MultiConfig cmQtAutoGen::MultiConfigType(std::string const& name)
+cmQtAutoGen::MultiConfigT cmQtAutoGen::MultiConfigType(std::string const& name)
{
if (name == mcNameSingle) {
- return MultiConfig::SINGLE;
+ return MultiConfigT::SINGLE;
}
- if (name == mcNameFull) {
- return MultiConfig::FULL;
+ if (name == mcNameMulti) {
+ return MultiConfigT::MULTI;
}
- return MultiConfig::WRAP;
+ return MultiConfigT::WRAPPER;
}
std::string cmQtAutoGen::Quoted(std::string const& text)
@@ -294,6 +141,33 @@ std::string cmQtAutoGen::Quoted(std::string const& text)
return res;
}
+std::string cmQtAutoGen::QuotedCommand(std::vector<std::string> const& command)
+{
+ std::string res;
+ for (std::string const& item : command) {
+ if (!res.empty()) {
+ res.push_back(' ');
+ }
+ std::string const cesc = cmQtAutoGen::Quoted(item);
+ if (item.empty() || (cesc.size() > (item.size() + 2)) ||
+ (cesc.find(' ') != std::string::npos)) {
+ res += cesc;
+ } else {
+ res += item;
+ }
+ }
+ return res;
+}
+
+std::string cmQtAutoGen::SubDirPrefix(std::string const& filename)
+{
+ std::string res(cmSystemTools::GetFilenamePath(filename));
+ if (!res.empty()) {
+ res += '/';
+ }
+ return res;
+}
+
std::string cmQtAutoGen::AppendFilenameSuffix(std::string const& filename,
std::string const& suffix)
{
@@ -333,27 +207,79 @@ void cmQtAutoGen::RccMergeOptions(std::vector<std::string>& baseOpts,
MergeOptions(baseOpts, newOpts, valueOpts, isQt5);
}
-bool cmQtAutoGen::RccListInputs(std::string const& rccCommand,
- std::vector<std::string> const& rccListOptions,
- std::string const& fileName,
- std::vector<std::string>& files,
- std::string* errorMessage)
+void cmQtAutoGen::RccListParseContent(std::string const& content,
+ std::vector<std::string>& files)
{
- bool allGood = false;
- if (cmSystemTools::FileExists(fileName.c_str())) {
- if (rccListOptions.empty()) {
- allGood = RccListInputsQt4(fileName, files, errorMessage);
- } else {
- allGood = RccListInputsQt5(rccCommand, rccListOptions, fileName, files,
- errorMessage);
+ cmsys::RegularExpression fileMatchRegex("(<file[^<]+)");
+ cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)");
+
+ const char* contentChars = content.c_str();
+ while (fileMatchRegex.find(contentChars)) {
+ std::string const qrcEntry = fileMatchRegex.match(1);
+ contentChars += qrcEntry.size();
+ {
+ fileReplaceRegex.find(qrcEntry);
+ std::string const tag = fileReplaceRegex.match(1);
+ files.push_back(qrcEntry.substr(tag.size()));
}
- } else {
- if (errorMessage != nullptr) {
- std::string& err = *errorMessage;
- err = "rcc resource file does not exist:\n ";
- err += cmQtAutoGen::Quoted(fileName);
- err += "\n";
+ }
+}
+
+bool cmQtAutoGen::RccListParseOutput(std::string const& rccStdOut,
+ std::string const& rccStdErr,
+ std::vector<std::string>& files,
+ std::string& error)
+{
+ // Lambda to strip CR characters
+ auto StripCR = [](std::string& line) {
+ std::string::size_type cr = line.find('\r');
+ if (cr != std::string::npos) {
+ line = line.substr(0, cr);
}
+ };
+
+ // Parse rcc std output
+ {
+ std::istringstream ostr(rccStdOut);
+ std::string oline;
+ while (std::getline(ostr, oline)) {
+ StripCR(oline);
+ if (!oline.empty()) {
+ files.push_back(oline);
+ }
+ }
+ }
+ // Parse rcc error output
+ {
+ std::istringstream estr(rccStdErr);
+ std::string eline;
+ while (std::getline(estr, eline)) {
+ StripCR(eline);
+ if (cmHasLiteralPrefix(eline, "RCC: Error in")) {
+ static std::string const searchString = "Cannot find file '";
+
+ std::string::size_type pos = eline.find(searchString);
+ if (pos == std::string::npos) {
+ error = "rcc lists unparsable output:\n";
+ error += cmQtAutoGen::Quoted(eline);
+ error += "\n";
+ return false;
+ }
+ pos += searchString.length();
+ std::string::size_type sz = eline.size() - pos - 1;
+ files.push_back(eline.substr(pos, sz));
+ }
+ }
+ }
+
+ return true;
+}
+
+void cmQtAutoGen::RccListConvertFullPath(std::string const& qrcFileDir,
+ std::vector<std::string>& files)
+{
+ for (std::string& entry : files) {
+ std::string tmp = cmSystemTools::CollapseCombinedPath(qrcFileDir, entry);
+ entry = std::move(tmp);
}
- return allGood;
}
diff --git a/Source/cmQtAutoGen.h b/Source/cmQtAutoGen.h
index e769e93..30ce0f6 100644
--- a/Source/cmQtAutoGen.h
+++ b/Source/cmQtAutoGen.h
@@ -9,14 +9,18 @@
#include <vector>
/** \class cmQtAutoGen
- * \brief Class used as namespace for QtAutogen related types and functions
+ * \brief Common base class for QtAutoGen classes
*/
class cmQtAutoGen
{
public:
- static std::string const listSep;
+ /// @brief Nested lists separator
+ static std::string const ListSep;
+ /// @brief Maximum number of parallel threads/processes in a generator
+ static unsigned int const ParallelMax;
- enum Generator
+ /// @brief AutoGen generator type
+ enum class GeneratorT
{
GEN, // General
MOC,
@@ -24,27 +28,33 @@ public:
RCC
};
- enum MultiConfig
+ /// @brief Multiconfiguration type
+ enum class MultiConfigT
{
- SINGLE, // Single configuration
- WRAP, // Multi configuration using wrapper files
- FULL // Full multi configuration using per config sources
+ SINGLE, // Single configuration
+ WRAPPER, // Multi configuration using wrapper files
+ MULTI // Multi configuration using per config sources
};
public:
/// @brief Returns the generator name
- static std::string const& GeneratorName(Generator genType);
+ static std::string const& GeneratorName(GeneratorT genType);
/// @brief Returns the generator name in upper case
- static std::string GeneratorNameUpper(Generator genType);
+ static std::string GeneratorNameUpper(GeneratorT genType);
/// @brief Returns the multi configuration name string
- static std::string const& MultiConfigName(MultiConfig config);
+ static std::string const& MultiConfigName(MultiConfigT config);
/// @brief Returns the multi configuration type
- static MultiConfig MultiConfigType(std::string const& name);
+ static MultiConfigT MultiConfigType(std::string const& name);
/// @brief Returns a the string escaped and enclosed in quotes
static std::string Quoted(std::string const& text);
+ static std::string QuotedCommand(std::vector<std::string> const& command);
+
+ /// @brief Returns the parent directory of the file with a "/" suffix
+ static std::string SubDirPrefix(std::string const& filename);
+
/// @brief Appends the suffix to the filename before the last dot
static std::string AppendFilenameSuffix(std::string const& filename,
std::string const& suffix);
@@ -59,14 +69,21 @@ public:
std::vector<std::string> const& newOpts,
bool isQt5);
- /// @brief Reads the resource files list from from a .qrc file
- /// @arg fileName Must be the absolute path of the .qrc file
- /// @return True if the rcc file was successfully read
- static bool RccListInputs(std::string const& rccCommand,
- std::vector<std::string> const& rccListOptions,
- std::string const& fileName,
- std::vector<std::string>& files,
- std::string* errorMessage = nullptr);
+ /// @brief Parses the content of a qrc file
+ ///
+ /// Use when rcc does not support the "--list" option
+ static void RccListParseContent(std::string const& content,
+ std::vector<std::string>& files);
+
+ /// @brief Parses the output of the "rcc --list ..." command
+ static bool RccListParseOutput(std::string const& rccStdOut,
+ std::string const& rccStdErr,
+ std::vector<std::string>& files,
+ std::string& error);
+
+ /// @brief Converts relative qrc entry paths to full paths
+ static void RccListConvertFullPath(std::string const& qrcFileDir,
+ std::vector<std::string>& files);
};
#endif
diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index de0ba4f..0b67981 100644
--- a/Source/cmQtAutoGeneratorInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -1,7 +1,7 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmQtAutoGen.h"
-#include "cmQtAutoGeneratorInitializer.h"
+#include "cmQtAutoGenInitializer.h"
#include "cmAlgorithms.h"
#include "cmCustomCommand.h"
@@ -24,6 +24,7 @@
#include "cm_sys_stat.h"
#include "cmake.h"
#include "cmsys/FStream.hxx"
+#include "cmsys/SystemInformation.hxx"
#include <algorithm>
#include <array>
@@ -52,6 +53,20 @@ inline static std::string GetSafeProperty(cmSourceFile const* sf,
return std::string(SafeString(sf->GetProperty(key)));
}
+static std::size_t GetParallelCPUCount()
+{
+ static std::size_t count = 0;
+ // Detect only on the first call
+ if (count == 0) {
+ cmsys::SystemInformation info;
+ info.RunCPUCheck();
+ count = info.GetNumberOfPhysicalCPU();
+ count = std::max<std::size_t>(count, 1);
+ count = std::min<std::size_t>(count, cmQtAutoGen::ParallelMax);
+ }
+ return count;
+}
+
static void AddDefinitionEscaped(cmMakefile* makefile, const char* key,
std::string const& value)
{
@@ -85,12 +100,12 @@ static void AddDefinitionEscaped(
seplist.push_back(std::move(blist));
}
makefile->AddDefinition(key, cmOutputConverter::EscapeForCMake(
- cmJoin(seplist, cmQtAutoGen::listSep))
+ cmJoin(seplist, cmQtAutoGen::ListSep))
.c_str());
}
static bool AddToSourceGroup(cmMakefile* makefile, std::string const& fileName,
- cmQtAutoGen::Generator genType)
+ cmQtAutoGen::GeneratorT genType)
{
cmSourceGroup* sourceGroup = nullptr;
// Acquire source group
@@ -101,10 +116,10 @@ static bool AddToSourceGroup(cmMakefile* makefile, std::string const& fileName,
std::array<std::string, 2> props;
// Use generator specific group name
switch (genType) {
- case cmQtAutoGen::MOC:
+ case cmQtAutoGen::GeneratorT::MOC:
props[0] = "AUTOMOC_SOURCE_GROUP";
break;
- case cmQtAutoGen::RCC:
+ case cmQtAutoGen::GeneratorT::RCC:
props[0] = "AUTORCC_SOURCE_GROUP";
break;
default:
@@ -211,7 +226,7 @@ static bool StaticLibraryCycle(cmGeneratorTarget const* targetOrigin,
return cycle;
}
-cmQtAutoGeneratorInitializer::cmQtAutoGeneratorInitializer(
+cmQtAutoGenInitializer::cmQtAutoGenInitializer(
cmGeneratorTarget* target, bool mocEnabled, bool uicEnabled, bool rccEnabled,
std::string const& qtVersionMajor)
: Target(target)
@@ -219,13 +234,13 @@ cmQtAutoGeneratorInitializer::cmQtAutoGeneratorInitializer(
, UicEnabled(uicEnabled)
, RccEnabled(rccEnabled)
, QtVersionMajor(qtVersionMajor)
- , MultiConfig(cmQtAutoGen::WRAP)
+ , MultiConfig(MultiConfigT::WRAPPER)
{
- this->QtVersionMinor = cmQtAutoGeneratorInitializer::GetQtMinorVersion(
- target, this->QtVersionMajor);
+ this->QtVersionMinor =
+ cmQtAutoGenInitializer::GetQtMinorVersion(target, this->QtVersionMajor);
}
-void cmQtAutoGeneratorInitializer::InitCustomTargets()
+void cmQtAutoGenInitializer::InitCustomTargets()
{
cmMakefile* makefile = this->Target->Target->GetMakefile();
cmLocalGenerator* localGen = this->Target->GetLocalGenerator();
@@ -240,19 +255,19 @@ void cmQtAutoGeneratorInitializer::InitCustomTargets()
// Multi configuration
{
if (!globalGen->IsMultiConfig()) {
- this->MultiConfig = cmQtAutoGen::SINGLE;
+ this->MultiConfig = MultiConfigT::SINGLE;
}
// FIXME: Xcode does not support per-config sources, yet.
// (EXCLUDED_SOURCE_FILE_NAMES)
// if (globalGen->GetName().find("Xcode") != std::string::npos) {
- // return cmQtAutoGen::FULL;
+ // return MultiConfigT::MULTI;
//}
// FIXME: Visual Studio does not support per-config sources, yet.
// (EXCLUDED_SOURCE_FILE_NAMES)
// if (globalGen->GetName().find("Visual Studio") != std::string::npos) {
- // return cmQtAutoGen::FULL;
+ // return MultiConfigT::MULTI;
//}
}
@@ -294,7 +309,7 @@ void cmQtAutoGeneratorInitializer::InitCustomTargets()
this->AutogenInfoFile += "/AutogenInfo.cmake";
this->AutogenSettingsFile = this->DirInfo;
- this->AutogenSettingsFile += "/AutogenOldSettings.cmake";
+ this->AutogenSettingsFile += "/AutogenOldSettings.txt";
}
// Autogen target FOLDER property
@@ -324,7 +339,7 @@ void cmQtAutoGeneratorInitializer::InitCustomTargets()
{
std::string base = this->DirInfo;
base += "/AutogenOldSettings";
- if (this->MultiConfig == cmQtAutoGen::SINGLE) {
+ if (this->MultiConfig == MultiConfigT::SINGLE) {
AddCleanFile(makefile, base.append(".cmake"));
} else {
for (std::string const& cfg : this->ConfigsList) {
@@ -340,7 +355,7 @@ void cmQtAutoGeneratorInitializer::InitCustomTargets()
// Add moc compilation to generated files list
if (this->MocEnabled) {
std::string const mocsComp = this->DirBuild + "/mocs_compilation.cpp";
- auto files = this->AddGeneratedSource(mocsComp, cmQtAutoGen::MOC);
+ auto files = this->AddGeneratedSource(mocsComp, GeneratorT::MOC);
for (std::string& file : files) {
autogenProvides.push_back(std::move(file));
}
@@ -349,7 +364,7 @@ void cmQtAutoGeneratorInitializer::InitCustomTargets()
// Add autogen includes directory to the origin target INCLUDE_DIRECTORIES
if (this->MocEnabled || this->UicEnabled) {
std::string includeDir = this->DirBuild + "/include";
- if (this->MultiConfig != cmQtAutoGen::SINGLE) {
+ if (this->MultiConfig != MultiConfigT::SINGLE) {
includeDir += "_$<CONFIG>";
}
this->Target->AddIncludeDirectory(includeDir, true);
@@ -560,10 +575,10 @@ void cmQtAutoGeneratorInitializer::InitCustomTargets()
msg += "For compatibility, CMake is excluding the GENERATED source "
"file(s):\n";
for (const std::string& absFile : generatedHeaders) {
- msg.append(" ").append(cmQtAutoGen::Quoted(absFile)).append("\n");
+ msg.append(" ").append(Quoted(absFile)).append("\n");
}
for (const std::string& absFile : generatedSources) {
- msg.append(" ").append(cmQtAutoGen::Quoted(absFile)).append("\n");
+ msg.append(" ").append(Quoted(absFile)).append("\n");
}
msg += "from processing by ";
msg += tools;
@@ -630,7 +645,7 @@ void cmQtAutoGeneratorInitializer::InitCustomTargets()
qrc.InfoFile = base;
qrc.InfoFile += "Info.cmake";
qrc.SettingsFile = base;
- qrc.SettingsFile += "Settings.cmake";
+ qrc.SettingsFile += "Settings.txt";
}
}
}
@@ -650,16 +665,16 @@ void cmQtAutoGeneratorInitializer::InitCustomTargets()
std::vector<std::string> nameOpts;
nameOpts.emplace_back("-name");
nameOpts.emplace_back(std::move(name));
- cmQtAutoGen::RccMergeOptions(opts, nameOpts, QtV5);
+ RccMergeOptions(opts, nameOpts, QtV5);
}
// Merge file option
- cmQtAutoGen::RccMergeOptions(opts, qrc.Options, QtV5);
+ RccMergeOptions(opts, qrc.Options, QtV5);
qrc.Options = std::move(opts);
}
for (Qrc& qrc : this->Qrcs) {
// Register file at target
std::vector<std::string> const ccOutput =
- this->AddGeneratedSource(qrc.RccFile, cmQtAutoGen::RCC);
+ this->AddGeneratedSource(qrc.RccFile, GeneratorT::RCC);
cmCustomCommandLines commandLines;
{
@@ -686,8 +701,9 @@ void cmQtAutoGeneratorInitializer::InitCustomTargets()
ccName += qrc.PathChecksum;
}
std::vector<std::string> ccDepends;
- // Add the .qrc file to the custom target dependencies
+ // Add the .qrc and info file to the custom target dependencies
ccDepends.push_back(qrc.QrcFile);
+ ccDepends.push_back(qrc.InfoFile);
cmTarget* autoRccTarget = makefile->AddUtilityCommand(
ccName, cmMakefile::TargetOrigin::Generator, true,
@@ -709,15 +725,14 @@ void cmQtAutoGeneratorInitializer::InitCustomTargets()
{
std::vector<std::string> ccByproducts;
std::vector<std::string> ccDepends;
- // Add the .qrc file to the custom command dependencies
+ // Add the .qrc and info file to the custom command dependencies
ccDepends.push_back(qrc.QrcFile);
+ ccDepends.push_back(qrc.InfoFile);
// Add the resource files to the dependencies
{
std::string error;
- if (cmQtAutoGen::RccListInputs(this->RccExecutable,
- this->RccListOptions, qrc.QrcFile,
- qrc.Resources, &error)) {
+ if (RccListInputs(qrc.QrcFile, qrc.Resources, error)) {
for (std::string const& fileName : qrc.Resources) {
// Add resource file to the custom command dependencies
ccDepends.push_back(fileName);
@@ -885,7 +900,7 @@ void cmQtAutoGeneratorInitializer::InitCustomTargets()
}
}
-void cmQtAutoGeneratorInitializer::SetupCustomTargets()
+void cmQtAutoGenInitializer::SetupCustomTargets()
{
cmMakefile* makefile = this->Target->Target->GetMakefile();
@@ -903,8 +918,16 @@ void cmQtAutoGeneratorInitializer::SetupCustomTargets()
// Basic setup
AddDefinitionEscaped(makefile, "_multi_config",
- cmQtAutoGen::MultiConfigName(this->MultiConfig));
+ MultiConfigName(this->MultiConfig));
AddDefinitionEscaped(makefile, "_build_dir", this->DirBuild);
+ {
+ std::string parallel = GetSafeProperty(this->Target, "AUTOGEN_PARALLEL");
+ // Autodetect number of CPUs
+ if (parallel.empty() || (parallel == "AUTO")) {
+ parallel = std::to_string(GetParallelCPUCount());
+ }
+ AddDefinitionEscaped(makefile, "_parallel", parallel);
+ }
if (this->MocEnabled || this->UicEnabled) {
AddDefinitionEscaped(makefile, "_qt_version_major", this->QtVersionMajor);
@@ -929,7 +952,7 @@ void cmQtAutoGeneratorInitializer::SetupCustomTargets()
// Create info directory on demand
if (!cmSystemTools::MakeDirectory(this->DirInfo)) {
std::string emsg = ("Could not create directory: ");
- emsg += cmQtAutoGen::Quoted(this->DirInfo);
+ emsg += Quoted(this->DirInfo);
cmSystemTools::Error(emsg.c_str());
}
@@ -951,7 +974,7 @@ void cmQtAutoGeneratorInitializer::SetupCustomTargets()
if (!ofs) {
// File open error
std::string error = "Internal CMake error when trying to open file: ";
- error += cmQtAutoGen::Quoted(fileName);
+ error += Quoted(fileName);
error += " for writing.";
cmSystemTools::Error(error.c_str());
}
@@ -984,11 +1007,11 @@ void cmQtAutoGeneratorInitializer::SetupCustomTargets()
OfsWriteMap("AM_MOC_INCLUDES", this->ConfigMocIncludes);
OfsWriteMap("AM_UIC_TARGET_OPTIONS", this->ConfigUicOptions);
// Settings files (only require for multi configuration generators)
- if (this->MultiConfig != cmQtAutoGen::SINGLE) {
+ if (this->MultiConfig != MultiConfigT::SINGLE) {
std::map<std::string, std::string> settingsFiles;
for (std::string const& cfg : this->ConfigsList) {
- settingsFiles[cfg] = cmQtAutoGen::AppendFilenameSuffix(
- this->AutogenSettingsFile, "_" + cfg);
+ settingsFiles[cfg] =
+ AppendFilenameSuffix(this->AutogenSettingsFile, "_" + cfg);
}
OfsWriteMap("AM_SETTINGS_FILE", settingsFiles);
}
@@ -1033,11 +1056,11 @@ void cmQtAutoGeneratorInitializer::SetupCustomTargets()
OfsWriteMap("ARCC_CONFIG_SUFFIX", configSuffixes);
// Settings files (only require for multi configuration generators)
- if (this->MultiConfig != cmQtAutoGen::SINGLE) {
+ if (this->MultiConfig != MultiConfigT::SINGLE) {
std::map<std::string, std::string> settingsFiles;
for (std::string const& cfg : this->ConfigsList) {
settingsFiles[cfg] =
- cmQtAutoGen::AppendFilenameSuffix(qrc.SettingsFile, "_" + cfg);
+ AppendFilenameSuffix(qrc.SettingsFile, "_" + cfg);
}
OfsWriteMap("ARCC_SETTINGS_FILE", settingsFiles);
}
@@ -1049,7 +1072,7 @@ void cmQtAutoGeneratorInitializer::SetupCustomTargets()
}
}
-void cmQtAutoGeneratorInitializer::SetupCustomTargetsMoc()
+void cmQtAutoGenInitializer::SetupCustomTargetsMoc()
{
cmLocalGenerator* localGen = this->Target->GetLocalGenerator();
cmMakefile* makefile = this->Target->Target->GetMakefile();
@@ -1148,7 +1171,7 @@ void cmQtAutoGeneratorInitializer::SetupCustomTargetsMoc()
}
}
-void cmQtAutoGeneratorInitializer::SetupCustomTargetsUic()
+void cmQtAutoGenInitializer::SetupCustomTargetsUic()
{
cmMakefile* makefile = this->Target->Target->GetMakefile();
@@ -1266,17 +1289,16 @@ void cmQtAutoGeneratorInitializer::SetupCustomTargetsUic()
}
}
-std::vector<std::string> cmQtAutoGeneratorInitializer::AddGeneratedSource(
- std::string const& filename, cmQtAutoGen::Generator genType)
+std::vector<std::string> cmQtAutoGenInitializer::AddGeneratedSource(
+ std::string const& filename, GeneratorT genType)
{
std::vector<std::string> genFiles;
// Register source file in makefile and source group
- if (this->MultiConfig != cmQtAutoGen::FULL) {
+ if (this->MultiConfig != MultiConfigT::MULTI) {
genFiles.push_back(filename);
} else {
for (std::string const& cfg : this->ConfigsList) {
- genFiles.push_back(
- cmQtAutoGen::AppendFilenameSuffix(filename, "_" + cfg));
+ genFiles.push_back(AppendFilenameSuffix(filename, "_" + cfg));
}
}
{
@@ -1292,14 +1314,14 @@ std::vector<std::string> cmQtAutoGeneratorInitializer::AddGeneratedSource(
}
// Add source file to target
- if (this->MultiConfig != cmQtAutoGen::FULL) {
+ if (this->MultiConfig != MultiConfigT::MULTI) {
this->Target->AddSource(filename);
} else {
for (std::string const& cfg : this->ConfigsList) {
std::string src = "$<$<CONFIG:";
src += cfg;
src += ">:";
- src += cmQtAutoGen::AppendFilenameSuffix(filename, "_" + cfg);
+ src += AppendFilenameSuffix(filename, "_" + cfg);
src += ">";
this->Target->AddSource(src);
}
@@ -1308,7 +1330,7 @@ std::vector<std::string> cmQtAutoGeneratorInitializer::AddGeneratedSource(
return genFiles;
}
-std::string cmQtAutoGeneratorInitializer::GetQtMajorVersion(
+std::string cmQtAutoGenInitializer::GetQtMajorVersion(
cmGeneratorTarget const* target)
{
cmMakefile* makefile = target->Target->GetMakefile();
@@ -1324,7 +1346,7 @@ std::string cmQtAutoGeneratorInitializer::GetQtMajorVersion(
return qtMajor;
}
-std::string cmQtAutoGeneratorInitializer::GetQtMinorVersion(
+std::string cmQtAutoGenInitializer::GetQtMinorVersion(
cmGeneratorTarget const* target, std::string const& qtVersionMajor)
{
cmMakefile* makefile = target->Target->GetMakefile();
@@ -1344,7 +1366,7 @@ std::string cmQtAutoGeneratorInitializer::GetQtMinorVersion(
return qtMinor;
}
-bool cmQtAutoGeneratorInitializer::QtVersionGreaterOrEqual(
+bool cmQtAutoGenInitializer::QtVersionGreaterOrEqual(
unsigned long requestMajor, unsigned long requestMinor) const
{
unsigned long majorUL(0);
@@ -1356,3 +1378,84 @@ bool cmQtAutoGeneratorInitializer::QtVersionGreaterOrEqual(
}
return false;
}
+
+/// @brief Reads the resource files list from from a .qrc file
+/// @arg fileName Must be the absolute path of the .qrc file
+/// @return True if the rcc file was successfully read
+bool cmQtAutoGenInitializer::RccListInputs(std::string const& fileName,
+ std::vector<std::string>& files,
+ std::string& error)
+{
+ if (!cmSystemTools::FileExists(fileName.c_str())) {
+ error = "rcc resource file does not exist:\n ";
+ error += Quoted(fileName);
+ error += "\n";
+ return false;
+ }
+ if (!RccListOptions.empty()) {
+ // Use rcc for file listing
+ if (RccExecutable.empty()) {
+ error = "rcc executable not available";
+ return false;
+ }
+
+ // Run rcc list command in the directory of the qrc file with the pathless
+ // qrc file name argument. This way rcc prints relative paths.
+ // This avoids issues on Windows when the qrc file is in a path that
+ // contains non-ASCII characters.
+ std::string const fileDir = cmSystemTools::GetFilenamePath(fileName);
+ std::string const fileNameName = cmSystemTools::GetFilenameName(fileName);
+
+ bool result = false;
+ int retVal = 0;
+ std::string rccStdOut;
+ std::string rccStdErr;
+ {
+ std::vector<std::string> cmd;
+ cmd.push_back(RccExecutable);
+ cmd.insert(cmd.end(), RccListOptions.begin(), RccListOptions.end());
+ cmd.push_back(fileNameName);
+ result = cmSystemTools::RunSingleCommand(
+ cmd, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(),
+ cmSystemTools::OUTPUT_NONE, 0.0, cmProcessOutput::Auto);
+ }
+ if (!result || retVal) {
+ error = "rcc list process failed for:\n ";
+ error += Quoted(fileName);
+ error += "\n";
+ error += rccStdOut;
+ error += "\n";
+ error += rccStdErr;
+ error += "\n";
+ return false;
+ }
+ if (!RccListParseOutput(rccStdOut, rccStdErr, files, error)) {
+ return false;
+ }
+ } else {
+ // We can't use rcc for the file listing.
+ // Read the qrc file content into string and parse it.
+ {
+ std::string qrcContents;
+ {
+ cmsys::ifstream ifs(fileName.c_str());
+ if (ifs) {
+ std::ostringstream osst;
+ osst << ifs.rdbuf();
+ qrcContents = osst.str();
+ } else {
+ error = "rcc file not readable:\n ";
+ error += Quoted(fileName);
+ error += "\n";
+ return false;
+ }
+ }
+ // Parse string content
+ RccListParseContent(qrcContents, files);
+ }
+ }
+
+ // Convert relative paths to absolute paths
+ RccListConvertFullPath(cmSystemTools::GetFilenamePath(fileName), files);
+ return true;
+}
diff --git a/Source/cmQtAutoGeneratorInitializer.h b/Source/cmQtAutoGenInitializer.h
index e06e1c4..a667017 100644
--- a/Source/cmQtAutoGeneratorInitializer.h
+++ b/Source/cmQtAutoGenInitializer.h
@@ -1,7 +1,7 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
-#ifndef cmQtAutoGeneratorInitializer_h
-#define cmQtAutoGeneratorInitializer_h
+#ifndef cmQtAutoGenInitializer_h
+#define cmQtAutoGenInitializer_h
#include "cmConfigure.h" // IWYU pragma: keep
#include "cmQtAutoGen.h"
@@ -13,7 +13,8 @@
class cmGeneratorTarget;
-class cmQtAutoGeneratorInitializer
+/// @brief Initializes the QtAutoGen generators
+class cmQtAutoGenInitializer : public cmQtAutoGen
{
public:
static std::string GetQtMajorVersion(cmGeneratorTarget const* target);
@@ -43,9 +44,9 @@ public:
};
public:
- cmQtAutoGeneratorInitializer(cmGeneratorTarget* target, bool mocEnabled,
- bool uicEnabled, bool rccEnabled,
- std::string const& qtVersionMajor);
+ cmQtAutoGenInitializer(cmGeneratorTarget* target, bool mocEnabled,
+ bool uicEnabled, bool rccEnabled,
+ std::string const& qtVersionMajor);
void InitCustomTargets();
void SetupCustomTargets();
@@ -55,11 +56,15 @@ private:
void SetupCustomTargetsUic();
std::vector<std::string> AddGeneratedSource(std::string const& filename,
- cmQtAutoGen::Generator genType);
+ GeneratorT genType);
bool QtVersionGreaterOrEqual(unsigned long requestMajor,
unsigned long requestMinor) const;
+ bool RccListInputs(std::string const& fileName,
+ std::vector<std::string>& files,
+ std::string& errorMessage);
+
private:
cmGeneratorTarget* Target;
bool MocEnabled;
@@ -73,7 +78,7 @@ private:
// Configurations
std::string ConfigDefault;
std::vector<std::string> ConfigsList;
- cmQtAutoGen::MultiConfig MultiConfig;
+ MultiConfigT MultiConfig;
// Names
std::string AutogenTargetName;
std::string AutogenFolder;
diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx
index ee0ddbc..5b2b6d0 100644
--- a/Source/cmQtAutoGenerator.cxx
+++ b/Source/cmQtAutoGenerator.cxx
@@ -4,7 +4,6 @@
#include "cmQtAutoGenerator.h"
#include "cmsys/FStream.hxx"
-#include "cmsys/Terminal.h"
#include "cmAlgorithms.h"
#include "cmGlobalGenerator.h"
@@ -14,108 +13,55 @@
#include "cmSystemTools.h"
#include "cmake.h"
-// -- Static functions
-
-static std::string HeadLine(std::string const& title)
-{
- std::string head = title;
- head += '\n';
- head.append(head.size() - 1, '-');
- head += '\n';
- return head;
-}
-
-static std::string QuotedCommand(std::vector<std::string> const& command)
-{
- std::string res;
- for (std::string const& item : command) {
- if (!res.empty()) {
- res.push_back(' ');
- }
- std::string const cesc = cmQtAutoGen::Quoted(item);
- if (item.empty() || (cesc.size() > (item.size() + 2)) ||
- (cesc.find(' ') != std::string::npos)) {
- res += cesc;
- } else {
- res += item;
- }
- }
- return res;
-}
+#include <algorithm>
// -- Class methods
-cmQtAutoGenerator::cmQtAutoGenerator()
- : Verbose(cmSystemTools::HasEnv("VERBOSE"))
- , ColorOutput(true)
+void cmQtAutoGenerator::Logger::SetVerbose(bool value)
{
- {
- std::string colorEnv;
- cmSystemTools::GetEnv("COLOR", colorEnv);
- if (!colorEnv.empty()) {
- this->ColorOutput = cmSystemTools::IsOn(colorEnv.c_str());
- }
- }
+ Verbose_ = value;
}
-bool cmQtAutoGenerator::Run(std::string const& infoFile,
- std::string const& config)
+void cmQtAutoGenerator::Logger::SetColorOutput(bool value)
{
- // Info settings
- this->InfoFile = infoFile;
- cmSystemTools::ConvertToUnixSlashes(this->InfoFile);
- this->InfoDir = cmSystemTools::GetFilenamePath(infoFile);
- this->InfoConfig = config;
-
- cmake cm(cmake::RoleScript);
- cm.SetHomeOutputDirectory(this->InfoDir);
- cm.SetHomeDirectory(this->InfoDir);
- cm.GetCurrentSnapshot().SetDefaultDefinitions();
- cmGlobalGenerator gg(&cm);
-
- cmStateSnapshot snapshot = cm.GetCurrentSnapshot();
- snapshot.GetDirectory().SetCurrentBinary(this->InfoDir);
- snapshot.GetDirectory().SetCurrentSource(this->InfoDir);
-
- auto makefile = cm::make_unique<cmMakefile>(&gg, snapshot);
- // The OLD/WARN behavior for policy CMP0053 caused a speed regression.
- // https://gitlab.kitware.com/cmake/cmake/issues/17570
- makefile->SetPolicyVersion("3.9");
- gg.SetCurrentMakefile(makefile.get());
-
- return this->Process(makefile.get());
+ ColorOutput_ = value;
}
-void cmQtAutoGenerator::LogBold(std::string const& message) const
+std::string cmQtAutoGenerator::Logger::HeadLine(std::string const& title)
{
- cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue |
- cmsysTerminal_Color_ForegroundBold,
- message.c_str(), true, this->ColorOutput);
+ std::string head = title;
+ head += '\n';
+ head.append(head.size() - 1, '-');
+ head += '\n';
+ return head;
}
-void cmQtAutoGenerator::LogInfo(cmQtAutoGen::Generator genType,
- std::string const& message) const
+void cmQtAutoGenerator::Logger::Info(GeneratorT genType,
+ std::string const& message)
{
- std::string msg = cmQtAutoGen::GeneratorName(genType);
+ std::string msg = GeneratorName(genType);
msg += ": ";
msg += message;
if (msg.back() != '\n') {
msg.push_back('\n');
}
- cmSystemTools::Stdout(msg.c_str(), msg.size());
+ {
+ std::lock_guard<std::mutex> lock(Mutex_);
+ cmSystemTools::Stdout(msg.c_str(), msg.size());
+ }
}
-void cmQtAutoGenerator::LogWarning(cmQtAutoGen::Generator genType,
- std::string const& message) const
+void cmQtAutoGenerator::Logger::Warning(GeneratorT genType,
+ std::string const& message)
{
- std::string msg = cmQtAutoGen::GeneratorName(genType);
- msg += " warning:";
+ std::string msg;
if (message.find('\n') == std::string::npos) {
// Single line message
- msg.push_back(' ');
+ msg += GeneratorName(genType);
+ msg += " warning: ";
} else {
// Multi line message
- msg.push_back('\n');
+ msg += HeadLine(GeneratorName(genType) + " warning");
}
// Message
msg += message;
@@ -123,55 +69,60 @@ void cmQtAutoGenerator::LogWarning(cmQtAutoGen::Generator genType,
msg.push_back('\n');
}
msg.push_back('\n');
- cmSystemTools::Stdout(msg.c_str(), msg.size());
+ {
+ std::lock_guard<std::mutex> lock(Mutex_);
+ cmSystemTools::Stdout(msg.c_str(), msg.size());
+ }
}
-void cmQtAutoGenerator::LogFileWarning(cmQtAutoGen::Generator genType,
- std::string const& filename,
- std::string const& message) const
+void cmQtAutoGenerator::Logger::WarningFile(GeneratorT genType,
+ std::string const& filename,
+ std::string const& message)
{
std::string msg = " ";
- msg += cmQtAutoGen::Quoted(filename);
+ msg += Quoted(filename);
msg.push_back('\n');
// Message
msg += message;
- this->LogWarning(genType, msg);
+ Warning(genType, msg);
}
-void cmQtAutoGenerator::LogError(cmQtAutoGen::Generator genType,
- std::string const& message) const
+void cmQtAutoGenerator::Logger::Error(GeneratorT genType,
+ std::string const& message)
{
std::string msg;
- msg.push_back('\n');
- msg += HeadLine(cmQtAutoGen::GeneratorName(genType) + " error");
+ msg += HeadLine(GeneratorName(genType) + " error");
// Message
msg += message;
if (msg.back() != '\n') {
msg.push_back('\n');
}
msg.push_back('\n');
- cmSystemTools::Stderr(msg.c_str(), msg.size());
+ {
+ std::lock_guard<std::mutex> lock(Mutex_);
+ cmSystemTools::Stderr(msg.c_str(), msg.size());
+ }
}
-void cmQtAutoGenerator::LogFileError(cmQtAutoGen::Generator genType,
- std::string const& filename,
- std::string const& message) const
+void cmQtAutoGenerator::Logger::ErrorFile(GeneratorT genType,
+ std::string const& filename,
+ std::string const& message)
{
std::string emsg = " ";
- emsg += cmQtAutoGen::Quoted(filename);
+ emsg += Quoted(filename);
emsg += '\n';
// Message
emsg += message;
- this->LogError(genType, emsg);
+ Error(genType, emsg);
}
-void cmQtAutoGenerator::LogCommandError(
- cmQtAutoGen::Generator genType, std::string const& message,
- std::vector<std::string> const& command, std::string const& output) const
+void cmQtAutoGenerator::Logger::ErrorCommand(
+ GeneratorT genType, std::string const& message,
+ std::vector<std::string> const& command, std::string const& output)
{
std::string msg;
msg.push_back('\n');
- msg += HeadLine(cmQtAutoGen::GeneratorName(genType) + " subprocess error");
+ msg += HeadLine(GeneratorName(genType) + " subprocess error");
msg += message;
if (msg.back() != '\n') {
msg.push_back('\n');
@@ -189,135 +140,495 @@ void cmQtAutoGenerator::LogCommandError(
msg.push_back('\n');
}
msg.push_back('\n');
- cmSystemTools::Stderr(msg.c_str(), msg.size());
+ {
+ std::lock_guard<std::mutex> lock(Mutex_);
+ cmSystemTools::Stderr(msg.c_str(), msg.size());
+ }
}
-/**
- * @brief Generates the parent directory of the given file on demand
- * @return True on success
- */
-bool cmQtAutoGenerator::MakeParentDirectory(cmQtAutoGen::Generator genType,
- std::string const& filename) const
+std::string cmQtAutoGenerator::FileSystem::RealPath(
+ std::string const& filename)
{
- bool success = true;
- std::string const dirName = cmSystemTools::GetFilenamePath(filename);
- if (!dirName.empty()) {
- if (!cmSystemTools::MakeDirectory(dirName)) {
- this->LogFileError(genType, filename,
- "Could not create parent directory");
- success = false;
- }
- }
- return success;
+ std::lock_guard<std::mutex> lock(Mutex_);
+ return cmSystemTools::GetRealPath(filename);
+}
+
+bool cmQtAutoGenerator::FileSystem::FileExists(std::string const& filename)
+{
+ std::lock_guard<std::mutex> lock(Mutex_);
+ return cmSystemTools::FileExists(filename);
}
-/**
- * @brief Tests if buildFile is older than sourceFile
- * @return True if buildFile is older than sourceFile.
- * False may indicate an error.
- */
-bool cmQtAutoGenerator::FileIsOlderThan(std::string const& buildFile,
- std::string const& sourceFile,
- std::string* error)
+bool cmQtAutoGenerator::FileSystem::FileIsOlderThan(
+ std::string const& buildFile, std::string const& sourceFile,
+ std::string* error)
{
+ bool res(false);
int result = 0;
- if (cmSystemTools::FileTimeCompare(buildFile, sourceFile, &result)) {
- return (result < 0);
+ {
+ std::lock_guard<std::mutex> lock(Mutex_);
+ res = cmSystemTools::FileTimeCompare(buildFile, sourceFile, &result);
}
- if (error != nullptr) {
- error->append(
- "File modification time comparison failed for the files\n ");
- error->append(cmQtAutoGen::Quoted(buildFile));
- error->append("\nand\n ");
- error->append(cmQtAutoGen::Quoted(sourceFile));
+ if (res) {
+ res = (result < 0);
+ } else {
+ if (error != nullptr) {
+ error->append(
+ "File modification time comparison failed for the files\n ");
+ error->append(Quoted(buildFile));
+ error->append("\nand\n ");
+ error->append(Quoted(sourceFile));
+ }
}
- return false;
+ return res;
}
-bool cmQtAutoGenerator::FileRead(std::string& content,
- std::string const& filename,
- std::string* error)
+bool cmQtAutoGenerator::FileSystem::FileRead(std::string& content,
+ std::string const& filename,
+ std::string* error)
{
bool success = false;
- if (cmSystemTools::FileExists(filename)) {
- std::size_t const length = cmSystemTools::FileLength(filename);
- cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary));
- if (ifs) {
- content.resize(length);
- ifs.read(&content.front(), content.size());
+ {
+ std::lock_guard<std::mutex> lock(Mutex_);
+ if (cmSystemTools::FileExists(filename)) {
+ std::size_t const length = cmSystemTools::FileLength(filename);
+ cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary));
if (ifs) {
- success = true;
- } else {
- content.clear();
- if (error != nullptr) {
- error->append("Reading from the file failed.");
+ content.resize(length);
+ ifs.read(&content.front(), content.size());
+ if (ifs) {
+ success = true;
+ } else {
+ content.clear();
+ if (error != nullptr) {
+ error->append("Reading from the file failed.");
+ }
}
+ } else if (error != nullptr) {
+ error->append("Opening the file for reading failed.");
}
} else if (error != nullptr) {
- error->append("Opening the file for reading failed.");
+ error->append("The file does not exist.");
}
- } else if (error != nullptr) {
- error->append("The file does not exist.");
}
return success;
}
-bool cmQtAutoGenerator::FileWrite(cmQtAutoGen::Generator genType,
- std::string const& filename,
- std::string const& content)
+bool cmQtAutoGenerator::FileSystem::FileRead(GeneratorT genType,
+ std::string& content,
+ std::string const& filename)
{
std::string error;
+ if (!FileRead(content, filename, &error)) {
+ Log()->ErrorFile(genType, filename, error);
+ return false;
+ }
+ return true;
+}
+
+bool cmQtAutoGenerator::FileSystem::FileWrite(std::string const& filename,
+ std::string const& content,
+ std::string* error)
+{
+ bool success = false;
// Make sure the parent directory exists
- if (this->MakeParentDirectory(genType, filename)) {
+ if (MakeParentDirectory(filename)) {
+ std::lock_guard<std::mutex> lock(Mutex_);
cmsys::ofstream outfile;
outfile.open(filename.c_str(),
(std::ios::out | std::ios::binary | std::ios::trunc));
if (outfile) {
outfile << content;
// Check for write errors
- if (!outfile.good()) {
- error = "File writing failed";
+ if (outfile.good()) {
+ success = true;
+ } else {
+ if (error != nullptr) {
+ error->assign("File writing failed");
+ }
}
} else {
- error = "Opening file for writing failed";
+ if (error != nullptr) {
+ error->assign("Opening file for writing failed");
+ }
+ }
+ } else {
+ if (error != nullptr) {
+ error->assign("Could not create parent directory");
}
}
- if (!error.empty()) {
- this->LogFileError(genType, filename, error);
+ return success;
+}
+
+bool cmQtAutoGenerator::FileSystem::FileWrite(GeneratorT genType,
+ std::string const& filename,
+ std::string const& content)
+{
+ std::string error;
+ if (!FileWrite(filename, content, &error)) {
+ Log()->ErrorFile(genType, filename, error);
return false;
}
return true;
}
-bool cmQtAutoGenerator::FileDiffers(std::string const& filename,
- std::string const& content)
+bool cmQtAutoGenerator::FileSystem::FileDiffers(std::string const& filename,
+ std::string const& content)
{
bool differs = true;
{
std::string oldContents;
- if (this->FileRead(oldContents, filename)) {
+ if (FileRead(oldContents, filename)) {
differs = (oldContents != content);
}
}
return differs;
}
-/**
- * @brief Runs a command and returns true on success
- * @return True on success
- */
-bool cmQtAutoGenerator::RunCommand(std::vector<std::string> const& command,
- std::string& output) const
-{
- // Log command
- if (this->Verbose) {
- std::string qcmd = QuotedCommand(command);
- qcmd.push_back('\n');
- cmSystemTools::Stdout(qcmd.c_str(), qcmd.size());
- }
- // Execute command
- int retVal = 0;
- bool res = cmSystemTools::RunSingleCommand(
- command, &output, &output, &retVal, nullptr, cmSystemTools::OUTPUT_NONE);
- return (res && (retVal == 0));
+bool cmQtAutoGenerator::FileSystem::FileRemove(std::string const& filename)
+{
+ std::lock_guard<std::mutex> lock(Mutex_);
+ return cmSystemTools::RemoveFile(filename);
+}
+
+bool cmQtAutoGenerator::FileSystem::Touch(std::string const& filename)
+{
+ std::lock_guard<std::mutex> lock(Mutex_);
+ return cmSystemTools::Touch(filename, false);
+}
+
+bool cmQtAutoGenerator::FileSystem::MakeDirectory(std::string const& dirname)
+{
+ std::lock_guard<std::mutex> lock(Mutex_);
+ return cmSystemTools::MakeDirectory(dirname);
+}
+
+bool cmQtAutoGenerator::FileSystem::MakeDirectory(GeneratorT genType,
+ std::string const& dirname)
+{
+ if (!MakeDirectory(dirname)) {
+ Log()->ErrorFile(genType, dirname, "Could not create directory");
+ return false;
+ }
+ return true;
+}
+
+bool cmQtAutoGenerator::FileSystem::MakeParentDirectory(
+ std::string const& filename)
+{
+ bool success = true;
+ std::string const dirName = cmSystemTools::GetFilenamePath(filename);
+ if (!dirName.empty()) {
+ success = MakeDirectory(dirName);
+ }
+ return success;
+}
+
+bool cmQtAutoGenerator::FileSystem::MakeParentDirectory(
+ GeneratorT genType, std::string const& filename)
+{
+ if (!MakeParentDirectory(filename)) {
+ Log()->ErrorFile(genType, filename, "Could not create parent directory");
+ return false;
+ }
+ return true;
+}
+
+int cmQtAutoGenerator::ReadOnlyProcessT::PipeT::init(uv_loop_t* uv_loop,
+ ReadOnlyProcessT* process)
+{
+ Process_ = process;
+ Target_ = nullptr;
+ return UVPipe_.init(*uv_loop, 0, this);
+}
+
+int cmQtAutoGenerator::ReadOnlyProcessT::PipeT::startRead(std::string* target)
+{
+ Target_ = target;
+ return uv_read_start(uv_stream(), &PipeT::UVAlloc, &PipeT::UVData);
+}
+
+void cmQtAutoGenerator::ReadOnlyProcessT::PipeT::reset()
+{
+ Process_ = nullptr;
+ Target_ = nullptr;
+ UVPipe_.reset();
+ Buffer_.clear();
+ Buffer_.shrink_to_fit();
+}
+
+void cmQtAutoGenerator::ReadOnlyProcessT::PipeT::UVAlloc(uv_handle_t* handle,
+ size_t suggestedSize,
+ uv_buf_t* buf)
+{
+ auto& pipe = *reinterpret_cast<PipeT*>(handle->data);
+ pipe.Buffer_.resize(suggestedSize);
+ buf->base = &pipe.Buffer_.front();
+ buf->len = pipe.Buffer_.size();
+}
+
+void cmQtAutoGenerator::ReadOnlyProcessT::PipeT::UVData(uv_stream_t* stream,
+ ssize_t nread,
+ const uv_buf_t* buf)
+{
+ auto& pipe = *reinterpret_cast<PipeT*>(stream->data);
+ if (nread > 0) {
+ // Append data to merged output
+ if ((buf->base != nullptr) && (pipe.Target_ != nullptr)) {
+ pipe.Target_->append(buf->base, nread);
+ }
+ } else if (nread < 0) {
+ // EOF or error
+ auto* proc = pipe.Process_;
+ // Check it this an unusual error
+ if (nread != UV_EOF) {
+ if (!proc->Result()->error()) {
+ proc->Result()->ErrorMessage =
+ "libuv reading from pipe failed with error code ";
+ proc->Result()->ErrorMessage += std::to_string(nread);
+ }
+ }
+ // Clear libuv pipe handle and try to finish
+ pipe.reset();
+ proc->UVTryFinish();
+ }
+}
+
+void cmQtAutoGenerator::ProcessResultT::reset()
+{
+ ExitStatus = 0;
+ TermSignal = 0;
+ if (!StdOut.empty()) {
+ StdOut.clear();
+ StdOut.shrink_to_fit();
+ }
+ if (!StdErr.empty()) {
+ StdErr.clear();
+ StdErr.shrink_to_fit();
+ }
+ if (!ErrorMessage.empty()) {
+ ErrorMessage.clear();
+ ErrorMessage.shrink_to_fit();
+ }
+}
+
+void cmQtAutoGenerator::ReadOnlyProcessT::setup(
+ ProcessResultT* result, bool mergedOutput,
+ std::vector<std::string> const& command, std::string const& workingDirectory)
+{
+ Setup_.WorkingDirectory = workingDirectory;
+ Setup_.Command = command;
+ Setup_.Result = result;
+ Setup_.MergedOutput = mergedOutput;
+}
+
+bool cmQtAutoGenerator::ReadOnlyProcessT::start(
+ uv_loop_t* uv_loop, std::function<void()>&& finishedCallback)
+{
+ if (IsStarted() || (Result() == nullptr)) {
+ return false;
+ }
+
+ // Reset result before the start
+ Result()->reset();
+
+ // Fill command string pointers
+ if (!Setup().Command.empty()) {
+ CommandPtr_.reserve(Setup().Command.size() + 1);
+ for (std::string const& arg : Setup().Command) {
+ CommandPtr_.push_back(arg.c_str());
+ }
+ CommandPtr_.push_back(nullptr);
+ } else {
+ Result()->ErrorMessage = "Empty command";
+ }
+
+ if (!Result()->error()) {
+ if (UVPipeOut_.init(uv_loop, this) != 0) {
+ Result()->ErrorMessage = "libuv stdout pipe initialization failed";
+ }
+ }
+ if (!Result()->error()) {
+ if (UVPipeErr_.init(uv_loop, this) != 0) {
+ Result()->ErrorMessage = "libuv stderr pipe initialization failed";
+ }
+ }
+ if (!Result()->error()) {
+ // -- Setup process stdio options
+ // stdin
+ UVOptionsStdIO_[0].flags = UV_IGNORE;
+ UVOptionsStdIO_[0].data.stream = nullptr;
+ // stdout
+ UVOptionsStdIO_[1].flags =
+ static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+ UVOptionsStdIO_[1].data.stream = UVPipeOut_.uv_stream();
+ // stderr
+ UVOptionsStdIO_[2].flags =
+ static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+ UVOptionsStdIO_[2].data.stream = UVPipeErr_.uv_stream();
+
+ // -- Setup process options
+ std::fill_n(reinterpret_cast<char*>(&UVOptions_), sizeof(UVOptions_), 0);
+ UVOptions_.exit_cb = &ReadOnlyProcessT::UVExit;
+ UVOptions_.file = CommandPtr_[0];
+ UVOptions_.args = const_cast<char**>(&CommandPtr_.front());
+ UVOptions_.cwd = Setup_.WorkingDirectory.c_str();
+ UVOptions_.flags = UV_PROCESS_WINDOWS_HIDE;
+ UVOptions_.stdio_count = static_cast<int>(UVOptionsStdIO_.size());
+ UVOptions_.stdio = &UVOptionsStdIO_.front();
+
+ // -- Spawn process
+ if (UVProcess_.spawn(*uv_loop, UVOptions_, this) != 0) {
+ Result()->ErrorMessage = "libuv process spawn failed";
+ }
+ }
+ // -- Start reading from stdio streams
+ if (!Result()->error()) {
+ if (UVPipeOut_.startRead(&Result()->StdOut) != 0) {
+ Result()->ErrorMessage = "libuv start reading from stdout pipe failed";
+ }
+ }
+ if (!Result()->error()) {
+ if (UVPipeErr_.startRead(Setup_.MergedOutput ? &Result()->StdOut
+ : &Result()->StdErr) != 0) {
+ Result()->ErrorMessage = "libuv start reading from stderr pipe failed";
+ }
+ }
+
+ if (!Result()->error()) {
+ IsStarted_ = true;
+ FinishedCallback_ = std::move(finishedCallback);
+ } else {
+ // Clear libuv handles and finish
+ UVProcess_.reset();
+ UVPipeOut_.reset();
+ UVPipeErr_.reset();
+ CommandPtr_.clear();
+ }
+
+ return IsStarted();
+}
+
+void cmQtAutoGenerator::ReadOnlyProcessT::UVExit(uv_process_t* handle,
+ int64_t exitStatus,
+ int termSignal)
+{
+ auto& proc = *reinterpret_cast<ReadOnlyProcessT*>(handle->data);
+ if (proc.IsStarted() && !proc.IsFinished()) {
+ // Set error message on demand
+ proc.Result()->ExitStatus = exitStatus;
+ proc.Result()->TermSignal = termSignal;
+ if (!proc.Result()->error()) {
+ if (termSignal != 0) {
+ proc.Result()->ErrorMessage = "Process was terminated by signal ";
+ proc.Result()->ErrorMessage +=
+ std::to_string(proc.Result()->TermSignal);
+ } else if (exitStatus != 0) {
+ proc.Result()->ErrorMessage = "Process failed with return value ";
+ proc.Result()->ErrorMessage +=
+ std::to_string(proc.Result()->ExitStatus);
+ }
+ }
+
+ // Reset process handle and try to finish
+ proc.UVProcess_.reset();
+ proc.UVTryFinish();
+ }
+}
+
+void cmQtAutoGenerator::ReadOnlyProcessT::UVTryFinish()
+{
+ // There still might be data in the pipes after the process has finished.
+ // Therefore check if the process is finished AND all pipes are closed before
+ // signaling the worker thread to continue.
+ if (UVProcess_.get() == nullptr) {
+ if (UVPipeOut_.uv_pipe() == nullptr) {
+ if (UVPipeErr_.uv_pipe() == nullptr) {
+ IsFinished_ = true;
+ FinishedCallback_();
+ }
+ }
+ }
+}
+
+cmQtAutoGenerator::cmQtAutoGenerator()
+ : FileSys_(&Logger_)
+{
+ // Initialize logger
+ Logger_.SetVerbose(cmSystemTools::HasEnv("VERBOSE"));
+ {
+ std::string colorEnv;
+ cmSystemTools::GetEnv("COLOR", colorEnv);
+ if (!colorEnv.empty()) {
+ Logger_.SetColorOutput(cmSystemTools::IsOn(colorEnv.c_str()));
+ } else {
+ Logger_.SetColorOutput(true);
+ }
+ }
+
+ // Initialize libuv loop
+ uv_disable_stdio_inheritance();
+#ifdef CMAKE_UV_SIGNAL_HACK
+ UVHackRAII_ = cm::make_unique<cmUVSignalHackRAII>();
+#endif
+ UVLoop_ = cm::make_unique<uv_loop_t>();
+ uv_loop_init(UVLoop());
+}
+
+cmQtAutoGenerator::~cmQtAutoGenerator()
+{
+ // Close libuv loop
+ uv_loop_close(UVLoop());
+}
+
+bool cmQtAutoGenerator::Run(std::string const& infoFile,
+ std::string const& config)
+{
+ // Info settings
+ InfoFile_ = infoFile;
+ cmSystemTools::ConvertToUnixSlashes(InfoFile_);
+ InfoDir_ = cmSystemTools::GetFilenamePath(infoFile);
+ InfoConfig_ = config;
+
+ bool success = false;
+ {
+ cmake cm(cmake::RoleScript);
+ cm.SetHomeOutputDirectory(InfoDir());
+ cm.SetHomeDirectory(InfoDir());
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cmGlobalGenerator gg(&cm);
+
+ cmStateSnapshot snapshot = cm.GetCurrentSnapshot();
+ snapshot.GetDirectory().SetCurrentBinary(InfoDir());
+ snapshot.GetDirectory().SetCurrentSource(InfoDir());
+
+ auto makefile = cm::make_unique<cmMakefile>(&gg, snapshot);
+ // The OLD/WARN behavior for policy CMP0053 caused a speed regression.
+ // https://gitlab.kitware.com/cmake/cmake/issues/17570
+ makefile->SetPolicyVersion("3.9");
+ gg.SetCurrentMakefile(makefile.get());
+ success = this->Init(makefile.get());
+ }
+ if (success) {
+ success = this->Process();
+ }
+ return success;
+}
+
+std::string cmQtAutoGenerator::SettingsFind(std::string const& content,
+ const char* key)
+{
+ std::string prefix(key);
+ prefix += ':';
+ std::string::size_type pos = content.find(prefix);
+ if (pos != std::string::npos) {
+ pos += prefix.size();
+ if (pos < content.size()) {
+ std::string::size_type posE = content.find('\n', pos);
+ if ((posE != std::string::npos) && (posE != pos)) {
+ return content.substr(pos, posE - pos);
+ }
+ }
+ }
+ return std::string();
}
diff --git a/Source/cmQtAutoGenerator.h b/Source/cmQtAutoGenerator.h
index 285340d..6b35234 100644
--- a/Source/cmQtAutoGenerator.h
+++ b/Source/cmQtAutoGenerator.h
@@ -6,71 +6,283 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include "cmQtAutoGen.h"
+#include "cmUVHandlePtr.h"
+#include "cm_uv.h"
+#include <array>
+#include <functional>
+#include <mutex>
+#include <stddef.h>
+#include <stdint.h>
#include <string>
#include <vector>
class cmMakefile;
-class cmQtAutoGenerator
+/// @brief Base class for QtAutoGen gernerators
+class cmQtAutoGenerator : public cmQtAutoGen
{
CM_DISABLE_COPY(cmQtAutoGenerator)
public:
+ // -- Types
+
+ /// @brief Thread safe logging
+ class Logger
+ {
+ public:
+ // -- Verbosity
+ bool Verbose() const { return this->Verbose_; }
+ void SetVerbose(bool value);
+ bool ColorOutput() const { return this->ColorOutput_; }
+ void SetColorOutput(bool value);
+ // -- Log info
+ void Info(GeneratorT genType, std::string const& message);
+ // -- Log warning
+ void Warning(GeneratorT genType, std::string const& message);
+ void WarningFile(GeneratorT genType, std::string const& filename,
+ std::string const& message);
+ // -- Log error
+ void Error(GeneratorT genType, std::string const& message);
+ void ErrorFile(GeneratorT genType, std::string const& filename,
+ std::string const& message);
+ void ErrorCommand(GeneratorT genType, std::string const& message,
+ std::vector<std::string> const& command,
+ std::string const& output);
+
+ private:
+ static std::string HeadLine(std::string const& title);
+
+ private:
+ std::mutex Mutex_;
+ bool volatile Verbose_ = false;
+ bool volatile ColorOutput_ = false;
+ };
+
+ /// @brief Thread safe file system interface
+ class FileSystem
+ {
+ public:
+ FileSystem(Logger* log)
+ : Log_(log)
+ {
+ }
+
+ Logger* Log() const { return Log_; }
+ std::string RealPath(std::string const& filename);
+ bool FileExists(std::string const& filename);
+ bool FileIsOlderThan(std::string const& buildFile,
+ std::string const& sourceFile,
+ std::string* error = nullptr);
+
+ bool FileRead(std::string& content, std::string const& filename,
+ std::string* error = nullptr);
+ /// @brief Error logging version
+ bool FileRead(GeneratorT genType, std::string& content,
+ std::string const& filename);
+
+ bool FileWrite(std::string const& filename, std::string const& content,
+ std::string* error = nullptr);
+ /// @brief Error logging version
+ bool FileWrite(GeneratorT genType, std::string const& filename,
+ std::string const& content);
+
+ bool FileDiffers(std::string const& filename, std::string const& content);
+
+ bool FileRemove(std::string const& filename);
+ bool Touch(std::string const& filename);
+
+ bool MakeDirectory(std::string const& dirname);
+ /// @brief Error logging version
+ bool MakeDirectory(GeneratorT genType, std::string const& dirname);
+
+ bool MakeParentDirectory(std::string const& filename);
+ /// @brief Error logging version
+ bool MakeParentDirectory(GeneratorT genType, std::string const& filename);
+
+ private:
+ std::mutex Mutex_;
+ Logger* Log_;
+ };
+
+ /// @brief Return value and output of an external process
+ struct ProcessResultT
+ {
+ void reset();
+ bool error() const
+ {
+ return (ExitStatus != 0) || (TermSignal != 0) || !ErrorMessage.empty();
+ }
+
+ std::int64_t ExitStatus = 0;
+ int TermSignal = 0;
+ std::string StdOut;
+ std::string StdErr;
+ std::string ErrorMessage;
+ };
+
+ /// @brief External process management class
+ struct ReadOnlyProcessT
+ {
+ // -- Types
+
+ /// @brief libuv pipe buffer class
+ class PipeT
+ {
+ public:
+ int init(uv_loop_t* uv_loop, ReadOnlyProcessT* process);
+ int startRead(std::string* target);
+ void reset();
+
+ // -- Libuv casts
+ uv_pipe_t* uv_pipe() { return UVPipe_.get(); }
+ uv_stream_t* uv_stream()
+ {
+ return reinterpret_cast<uv_stream_t*>(uv_pipe());
+ }
+ uv_handle_t* uv_handle()
+ {
+ return reinterpret_cast<uv_handle_t*>(uv_pipe());
+ }
+
+ // -- Libuv callbacks
+ static void UVAlloc(uv_handle_t* handle, size_t suggestedSize,
+ uv_buf_t* buf);
+ static void UVData(uv_stream_t* stream, ssize_t nread,
+ const uv_buf_t* buf);
+
+ private:
+ ReadOnlyProcessT* Process_ = nullptr;
+ std::string* Target_ = nullptr;
+ std::vector<char> Buffer_;
+ cm::uv_pipe_ptr UVPipe_;
+ };
+
+ /// @brief Process settings
+ struct SetupT
+ {
+ std::string WorkingDirectory;
+ std::vector<std::string> Command;
+ ProcessResultT* Result = nullptr;
+ bool MergedOutput = false;
+ };
+
+ // -- Constructor
+ ReadOnlyProcessT() = default;
+
+ // -- Const accessors
+ const SetupT& Setup() const { return Setup_; }
+ ProcessResultT* Result() const { return Setup_.Result; }
+ bool IsStarted() const { return IsStarted_; }
+ bool IsFinished() const { return IsFinished_; }
+
+ // -- Runtime
+ void setup(ProcessResultT* result, bool mergedOutput,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory = std::string());
+ bool start(uv_loop_t* uv_loop, std::function<void()>&& finishedCallback);
+
+ private:
+ // -- Friends
+ friend class PipeT;
+ // -- Libuv callbacks
+ static void UVExit(uv_process_t* handle, int64_t exitStatus,
+ int termSignal);
+ void UVTryFinish();
+
+ // -- Setup
+ SetupT Setup_;
+ // -- Runtime
+ bool IsStarted_ = false;
+ bool IsFinished_ = false;
+ std::function<void()> FinishedCallback_;
+ std::vector<const char*> CommandPtr_;
+ std::array<uv_stdio_container_t, 3> UVOptionsStdIO_;
+ uv_process_options_t UVOptions_;
+ cm::uv_process_ptr UVProcess_;
+ PipeT UVPipeOut_;
+ PipeT UVPipeErr_;
+ };
+
+#if defined(CMAKE_USE_SYSTEM_LIBUV) && !defined(_WIN32) && \
+ UV_VERSION_MAJOR == 1 && UV_VERSION_MINOR < 19
+#define CMAKE_UV_SIGNAL_HACK
+ /*
+ libuv does not use SA_RESTART on its signal handler, but C++ streams
+ depend on it for reliable i/o operations. This RAII helper convinces
+ libuv to install its handler, and then revises the handler to add the
+ SA_RESTART flag. We use a distinct uv loop that never runs to avoid
+ ever really getting a callback. libuv may fill the hack loop's signal
+ pipe and then stop writing, but that won't break any real loops.
+ */
+ class cmUVSignalHackRAII
+ {
+ uv_loop_t HackLoop;
+ cm::uv_signal_ptr HackSignal;
+ static void HackCB(uv_signal_t*, int) {}
+ public:
+ cmUVSignalHackRAII()
+ {
+ uv_loop_init(&this->HackLoop);
+ this->HackSignal.init(this->HackLoop);
+ this->HackSignal.start(HackCB, SIGCHLD);
+ struct sigaction hack_sa;
+ sigaction(SIGCHLD, NULL, &hack_sa);
+ if (!(hack_sa.sa_flags & SA_RESTART)) {
+ hack_sa.sa_flags |= SA_RESTART;
+ sigaction(SIGCHLD, &hack_sa, NULL);
+ }
+ }
+ ~cmUVSignalHackRAII()
+ {
+ this->HackSignal.stop();
+ uv_loop_close(&this->HackLoop);
+ }
+ };
+#endif
+
+public:
+ // -- Constructors
cmQtAutoGenerator();
- virtual ~cmQtAutoGenerator() = default;
+ virtual ~cmQtAutoGenerator();
+
+ // -- Run
bool Run(std::string const& infoFile, std::string const& config);
- std::string const& GetInfoFile() const { return InfoFile; }
- std::string const& GetInfoDir() const { return InfoDir; }
- std::string const& GetInfoConfig() const { return InfoConfig; }
- bool GetVerbose() const { return Verbose; }
+ // -- Accessors
+ // Logging
+ Logger& Log() { return Logger_; }
+ // File System
+ FileSystem& FileSys() { return FileSys_; }
+ // InfoFile
+ std::string const& InfoFile() const { return InfoFile_; }
+ std::string const& InfoDir() const { return InfoDir_; }
+ std::string const& InfoConfig() const { return InfoConfig_; }
+ // libuv loop
+ uv_loop_t* UVLoop() { return UVLoop_.get(); }
+ cm::uv_async_ptr& UVRequest() { return UVRequest_; }
-protected:
- // -- Central processing
- virtual bool Process(cmMakefile* makefile) = 0;
-
- // -- Log info
- void LogBold(std::string const& message) const;
- void LogInfo(cmQtAutoGen::Generator genType,
- std::string const& message) const;
- // -- Log warning
- void LogWarning(cmQtAutoGen::Generator genType,
- std::string const& message) const;
- void LogFileWarning(cmQtAutoGen::Generator genType,
- std::string const& filename,
- std::string const& message) const;
- // -- Log error
- void LogError(cmQtAutoGen::Generator genType,
- std::string const& message) const;
- void LogFileError(cmQtAutoGen::Generator genType,
- std::string const& filename,
- std::string const& message) const;
- void LogCommandError(cmQtAutoGen::Generator genType,
- std::string const& message,
- std::vector<std::string> const& command,
- std::string const& output) const;
// -- Utility
- bool MakeParentDirectory(cmQtAutoGen::Generator genType,
- std::string const& filename) const;
- bool FileIsOlderThan(std::string const& buildFile,
- std::string const& sourceFile,
- std::string* error = nullptr);
- bool FileRead(std::string& content, std::string const& filename,
- std::string* error = nullptr);
- bool FileWrite(cmQtAutoGen::Generator genType, std::string const& filename,
- std::string const& content);
- bool FileDiffers(std::string const& filename, std::string const& content);
- bool RunCommand(std::vector<std::string> const& command,
- std::string& output) const;
+ static std::string SettingsFind(std::string const& content, const char* key);
+
+protected:
+ // -- Abstract processing interface
+ virtual bool Init(cmMakefile* makefile) = 0;
+ virtual bool Process() = 0;
private:
+ // -- Logging
+ Logger Logger_;
+ FileSystem FileSys_;
// -- Info settings
- std::string InfoFile;
- std::string InfoDir;
- std::string InfoConfig;
- // -- Settings
- bool Verbose;
- bool ColorOutput;
+ std::string InfoFile_;
+ std::string InfoDir_;
+ std::string InfoConfig_;
+// -- libuv loop
+#ifdef CMAKE_UV_SIGNAL_HACK
+ std::unique_ptr<cmUVSignalHackRAII> UVHackRAII_;
+#endif
+ std::unique_ptr<uv_loop_t> UVLoop_;
+ cm::uv_async_ptr UVRequest_;
};
#endif
diff --git a/Source/cmQtAutoGeneratorMocUic.cxx b/Source/cmQtAutoGeneratorMocUic.cxx
index bce148e..4b02e0b 100644
--- a/Source/cmQtAutoGeneratorMocUic.cxx
+++ b/Source/cmQtAutoGeneratorMocUic.cxx
@@ -5,16 +5,15 @@
#include <algorithm>
#include <array>
+#include <functional>
#include <list>
#include <memory>
#include <sstream>
-#include <string.h>
#include <utility>
#include "cmAlgorithms.h"
#include "cmCryptoHash.h"
#include "cmMakefile.h"
-#include "cmOutputConverter.h"
#include "cmSystemTools.h"
#include "cmake.h"
@@ -22,51 +21,1126 @@
#include <unistd.h>
#endif
-// -- Static variables
+// -- Class methods
-static const char* SettingsKeyMoc = "AM_MOC_SETTINGS_HASH";
-static const char* SettingsKeyUic = "AM_UIC_SETTINGS_HASH";
+std::string cmQtAutoGeneratorMocUic::BaseSettingsT::AbsoluteBuildPath(
+ std::string const& relativePath) const
+{
+ return cmSystemTools::CollapseCombinedPath(AutogenBuildDir, relativePath);
+}
-// -- Static functions
+/**
+ * @brief Tries to find the header file to the given file base path by
+ * appending different header extensions
+ * @return True on success
+ */
+bool cmQtAutoGeneratorMocUic::BaseSettingsT::FindHeader(
+ std::string& header, std::string const& testBasePath) const
+{
+ for (std::string const& ext : HeaderExtensions) {
+ std::string testFilePath(testBasePath);
+ testFilePath.push_back('.');
+ testFilePath += ext;
+ if (FileSys->FileExists(testFilePath)) {
+ header = testFilePath;
+ return true;
+ }
+ }
+ return false;
+}
-static std::string SubDirPrefix(std::string const& fileName)
+bool cmQtAutoGeneratorMocUic::MocSettingsT::skipped(
+ std::string const& fileName) const
{
- std::string res(cmSystemTools::GetFilenamePath(fileName));
- if (!res.empty()) {
- res += '/';
+ return (!Enabled || (SkipList.find(fileName) != SkipList.end()));
+}
+
+/**
+ * @brief Returns the first relevant Qt macro name found in the given C++ code
+ * @return The name of the Qt macro or an empty string
+ */
+std::string cmQtAutoGeneratorMocUic::MocSettingsT::FindMacro(
+ std::string const& content) const
+{
+ for (KeyExpT const& filter : MacroFilters) {
+ // Run a simple find string operation before the expensive
+ // regular expression check
+ if (content.find(filter.Key) != std::string::npos) {
+ cmsys::RegularExpressionMatch match;
+ if (filter.Exp.find(content.c_str(), match)) {
+ // Return macro name on demand
+ return filter.Key;
+ }
+ }
+ }
+ return std::string();
+}
+
+std::string cmQtAutoGeneratorMocUic::MocSettingsT::MacrosString() const
+{
+ std::string res;
+ const auto itB = MacroFilters.cbegin();
+ const auto itE = MacroFilters.cend();
+ const auto itL = itE - 1;
+ auto itC = itB;
+ for (; itC != itE; ++itC) {
+ // Separator
+ if (itC != itB) {
+ if (itC != itL) {
+ res += ", ";
+ } else {
+ res += " or ";
+ }
+ }
+ // Key
+ res += itC->Key;
}
return res;
}
-static bool ListContains(std::vector<std::string> const& list,
- std::string const& entry)
+std::string cmQtAutoGeneratorMocUic::MocSettingsT::FindIncludedFile(
+ std::string const& sourcePath, std::string const& includeString) const
+{
+ // Search in vicinity of the source
+ {
+ std::string testPath = sourcePath;
+ testPath += includeString;
+ if (FileSys->FileExists(testPath)) {
+ return FileSys->RealPath(testPath);
+ }
+ }
+ // Search in include directories
+ for (std::string const& path : IncludePaths) {
+ std::string fullPath = path;
+ fullPath.push_back('/');
+ fullPath += includeString;
+ if (FileSys->FileExists(fullPath)) {
+ return FileSys->RealPath(fullPath);
+ }
+ }
+ // Return empty string
+ return std::string();
+}
+
+void cmQtAutoGeneratorMocUic::MocSettingsT::FindDependencies(
+ std::string const& content, std::set<std::string>& depends) const
{
- return (std::find(list.begin(), list.end(), entry) != list.end());
+ if (!DependFilters.empty() && !content.empty()) {
+ for (KeyExpT const& filter : DependFilters) {
+ // Run a simple find string check
+ if (content.find(filter.Key) != std::string::npos) {
+ // Run the expensive regular expression check loop
+ const char* contentChars = content.c_str();
+ cmsys::RegularExpressionMatch match;
+ while (filter.Exp.find(contentChars, match)) {
+ {
+ std::string dep = match.match(1);
+ if (!dep.empty()) {
+ depends.emplace(std::move(dep));
+ }
+ }
+ contentChars += match.end();
+ }
+ }
+ }
+ }
}
-// -- Class methods
+bool cmQtAutoGeneratorMocUic::UicSettingsT::skipped(
+ std::string const& fileName) const
+{
+ return (!Enabled || (SkipList.find(fileName) != SkipList.end()));
+}
+
+void cmQtAutoGeneratorMocUic::JobParseT::Process(WorkerT& wrk)
+{
+ if (AutoMoc && Header) {
+ // Don't parse header for moc if the file is included by a source already
+ if (wrk.Gen().ParallelMocIncluded(FileName)) {
+ AutoMoc = false;
+ }
+ }
+
+ if (AutoMoc || AutoUic) {
+ std::string error;
+ MetaT meta;
+ if (wrk.FileSys().FileRead(meta.Content, FileName, &error)) {
+ if (!meta.Content.empty()) {
+ meta.FileDir = SubDirPrefix(FileName);
+ meta.FileBase =
+ cmSystemTools::GetFilenameWithoutLastExtension(FileName);
+
+ bool success = true;
+ if (AutoMoc) {
+ if (Header) {
+ success = ParseMocHeader(wrk, meta);
+ } else {
+ success = ParseMocSource(wrk, meta);
+ }
+ }
+ if (AutoUic && success) {
+ ParseUic(wrk, meta);
+ }
+ } else {
+ wrk.LogFileWarning(GeneratorT::GEN, FileName,
+ "The source file is empty");
+ }
+ } else {
+ wrk.LogFileError(GeneratorT::GEN, FileName,
+ "Could not read the file: " + error);
+ }
+ }
+}
+
+bool cmQtAutoGeneratorMocUic::JobParseT::ParseMocSource(WorkerT& wrk,
+ MetaT const& meta)
+{
+ struct JobPre
+ {
+ bool self; // source file is self
+ bool underscore; // "moc_" style include
+ std::string SourceFile;
+ std::string IncludeString;
+ };
+
+ struct MocInclude
+ {
+ std::string Inc; // full include string
+ std::string Dir; // include string directory
+ std::string Base; // include string file base
+ };
+
+ // Check if this source file contains a relevant macro
+ std::string const ownMacro = wrk.Moc().FindMacro(meta.Content);
+
+ // Extract moc includes from file
+ std::deque<MocInclude> mocIncsUsc;
+ std::deque<MocInclude> mocIncsDot;
+ {
+ if (meta.Content.find("moc") != std::string::npos) {
+ const char* contentChars = meta.Content.c_str();
+ cmsys::RegularExpressionMatch match;
+ while (wrk.Moc().RegExpInclude.find(contentChars, match)) {
+ std::string incString = match.match(1);
+ std::string incDir(SubDirPrefix(incString));
+ std::string incBase =
+ cmSystemTools::GetFilenameWithoutLastExtension(incString);
+ if (cmHasLiteralPrefix(incBase, "moc_")) {
+ // moc_<BASE>.cxx
+ // Remove the moc_ part from the base name
+ mocIncsUsc.emplace_back(MocInclude{
+ std::move(incString), std::move(incDir), incBase.substr(4) });
+ } else {
+ // <BASE>.moc
+ mocIncsDot.emplace_back(MocInclude{
+ std::move(incString), std::move(incDir), std::move(incBase) });
+ }
+ // Forward content pointer
+ contentChars += match.end();
+ }
+ }
+ }
+
+ // Check if there is anything to do
+ if (ownMacro.empty() && mocIncsUsc.empty() && mocIncsDot.empty()) {
+ return true;
+ }
+
+ bool ownDotMocIncluded = false;
+ bool ownMocUscIncluded = false;
+ std::deque<JobPre> jobs;
+
+ // Process moc_<BASE>.cxx includes
+ for (const MocInclude& mocInc : mocIncsUsc) {
+ std::string const header =
+ MocFindIncludedHeader(wrk, meta.FileDir, mocInc.Dir + mocInc.Base);
+ if (!header.empty()) {
+ // Check if header is skipped
+ if (wrk.Moc().skipped(header)) {
+ continue;
+ }
+ // Register moc job
+ const bool ownMoc = (mocInc.Base == meta.FileBase);
+ jobs.emplace_back(JobPre{ ownMoc, true, header, mocInc.Inc });
+ // Store meta information for relaxed mode
+ if (ownMoc) {
+ ownMocUscIncluded = true;
+ }
+ } else {
+ {
+ std::string emsg = "The file includes the moc file ";
+ emsg += Quoted(mocInc.Inc);
+ emsg += ", but the header ";
+ emsg += Quoted(MocStringHeaders(wrk, mocInc.Base));
+ emsg += " could not be found.";
+ wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
+ }
+ return false;
+ }
+ }
+
+ // Process <BASE>.moc includes
+ for (const MocInclude& mocInc : mocIncsDot) {
+ const bool ownMoc = (mocInc.Base == meta.FileBase);
+ if (wrk.Moc().RelaxedMode) {
+ // Relaxed mode
+ if (!ownMacro.empty() && ownMoc) {
+ // Add self
+ jobs.emplace_back(JobPre{ ownMoc, false, FileName, mocInc.Inc });
+ ownDotMocIncluded = true;
+ } else {
+ // In relaxed mode try to find a header instead but issue a warning.
+ // This is for KDE4 compatibility
+ std::string const header =
+ MocFindIncludedHeader(wrk, meta.FileDir, mocInc.Dir + mocInc.Base);
+ if (!header.empty()) {
+ // Check if header is skipped
+ if (wrk.Moc().skipped(header)) {
+ continue;
+ }
+ // Register moc job
+ jobs.emplace_back(JobPre{ ownMoc, false, header, mocInc.Inc });
+ if (ownMacro.empty()) {
+ if (ownMoc) {
+ std::string emsg = "The file includes the moc file ";
+ emsg += Quoted(mocInc.Inc);
+ emsg += ", but does not contain a ";
+ emsg += wrk.Moc().MacrosString();
+ emsg += " macro.\nRunning moc on\n ";
+ emsg += Quoted(header);
+ emsg += "!\nBetter include ";
+ emsg += Quoted("moc_" + mocInc.Base + ".cpp");
+ emsg += " for a compatibility with strict mode.\n"
+ "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n";
+ wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg);
+ } else {
+ std::string emsg = "The file includes the moc file ";
+ emsg += Quoted(mocInc.Inc);
+ emsg += " instead of ";
+ emsg += Quoted("moc_" + mocInc.Base + ".cpp");
+ emsg += ".\nRunning moc on\n ";
+ emsg += Quoted(header);
+ emsg += "!\nBetter include ";
+ emsg += Quoted("moc_" + mocInc.Base + ".cpp");
+ emsg += " for compatibility with strict mode.\n"
+ "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n";
+ wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg);
+ }
+ }
+ } else {
+ {
+ std::string emsg = "The file includes the moc file ";
+ emsg += Quoted(mocInc.Inc);
+ emsg += ", which seems to be the moc file from a different "
+ "source file.\nCMAKE_AUTOMOC_RELAXED_MODE: Also a "
+ "matching header ";
+ emsg += Quoted(MocStringHeaders(wrk, mocInc.Base));
+ emsg += " could not be found.";
+ wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
+ }
+ return false;
+ }
+ }
+ } else {
+ // Strict mode
+ if (ownMoc) {
+ // Include self
+ jobs.emplace_back(JobPre{ ownMoc, false, FileName, mocInc.Inc });
+ ownDotMocIncluded = true;
+ // Accept but issue a warning if moc isn't required
+ if (ownMacro.empty()) {
+ std::string emsg = "The file includes the moc file ";
+ emsg += Quoted(mocInc.Inc);
+ emsg += ", but does not contain a ";
+ emsg += wrk.Moc().MacrosString();
+ emsg += " macro.";
+ wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg);
+ }
+ } else {
+ // Don't allow <BASE>.moc include other than self in strict mode
+ {
+ std::string emsg = "The file includes the moc file ";
+ emsg += Quoted(mocInc.Inc);
+ emsg += ", which seems to be the moc file from a different "
+ "source file.\nThis is not supported. Include ";
+ emsg += Quoted(meta.FileBase + ".moc");
+ emsg += " to run moc on this source file.";
+ wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
+ }
+ return false;
+ }
+ }
+ }
+
+ if (!ownMacro.empty() && !ownDotMocIncluded) {
+ // In this case, check whether the scanned file itself contains a
+ // Q_OBJECT.
+ // If this is the case, the moc_foo.cpp should probably be generated from
+ // foo.cpp instead of foo.h, because otherwise it won't build.
+ // But warn, since this is not how it is supposed to be used.
+ // This is for KDE4 compatibility.
+ if (wrk.Moc().RelaxedMode && ownMocUscIncluded) {
+ JobPre uscJobPre;
+ // Remove underscore job request
+ {
+ auto itC = jobs.begin();
+ auto itE = jobs.end();
+ for (; itC != itE; ++itC) {
+ JobPre& job(*itC);
+ if (job.self && job.underscore) {
+ uscJobPre = std::move(job);
+ jobs.erase(itC);
+ break;
+ }
+ }
+ }
+ // Issue a warning
+ {
+ std::string emsg = "The file contains a ";
+ emsg += ownMacro;
+ emsg += " macro, but does not include ";
+ emsg += Quoted(meta.FileBase + ".moc");
+ emsg += ". Instead it includes ";
+ emsg += Quoted(uscJobPre.IncludeString);
+ emsg += ".\nRunning moc on\n ";
+ emsg += Quoted(FileName);
+ emsg += "!\nBetter include ";
+ emsg += Quoted(meta.FileBase + ".moc");
+ emsg += " for compatibility with strict mode.\n"
+ "(CMAKE_AUTOMOC_RELAXED_MODE warning)";
+ wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg);
+ }
+ // Add own source job
+ jobs.emplace_back(
+ JobPre{ true, false, FileName, uscJobPre.IncludeString });
+ } else {
+ // Otherwise always error out since it will not compile.
+ {
+ std::string emsg = "The file contains a ";
+ emsg += ownMacro;
+ emsg += " macro, but does not include ";
+ emsg += Quoted(meta.FileBase + ".moc");
+ emsg += "!\nConsider to\n - add #include \"";
+ emsg += meta.FileBase;
+ emsg += ".moc\"\n - enable SKIP_AUTOMOC for this file";
+ wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
+ }
+ return false;
+ }
+ }
+
+ // Convert pre jobs to actual jobs
+ for (JobPre& jobPre : jobs) {
+ JobHandleT jobHandle(new JobMocT(std::move(jobPre.SourceFile), FileName,
+ std::move(jobPre.IncludeString)));
+ if (jobPre.self) {
+ // Read depdendencies from this source
+ static_cast<JobMocT&>(*jobHandle).FindDependencies(wrk, meta.Content);
+ }
+ if (!wrk.Gen().ParallelJobPushMoc(jobHandle)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoGeneratorMocUic::JobParseT::ParseMocHeader(WorkerT& wrk,
+ MetaT const& meta)
+{
+ bool success = true;
+ std::string const macroName = wrk.Moc().FindMacro(meta.Content);
+ if (!macroName.empty()) {
+ JobHandleT jobHandle(
+ new JobMocT(std::string(FileName), std::string(), std::string()));
+ // Read depdendencies from this source
+ static_cast<JobMocT&>(*jobHandle).FindDependencies(wrk, meta.Content);
+ success = wrk.Gen().ParallelJobPushMoc(jobHandle);
+ }
+ return success;
+}
+
+std::string cmQtAutoGeneratorMocUic::JobParseT::MocStringHeaders(
+ WorkerT& wrk, std::string const& fileBase) const
+{
+ std::string res = fileBase;
+ res += ".{";
+ res += cmJoin(wrk.Base().HeaderExtensions, ",");
+ res += "}";
+ return res;
+}
+
+std::string cmQtAutoGeneratorMocUic::JobParseT::MocFindIncludedHeader(
+ WorkerT& wrk, std::string const& includerDir, std::string const& includeBase)
+{
+ std::string header;
+ // Search in vicinity of the source
+ if (!wrk.Base().FindHeader(header, includerDir + includeBase)) {
+ // Search in include directories
+ for (std::string const& path : wrk.Moc().IncludePaths) {
+ std::string fullPath = path;
+ fullPath.push_back('/');
+ fullPath += includeBase;
+ if (wrk.Base().FindHeader(header, fullPath)) {
+ break;
+ }
+ }
+ }
+ // Sanitize
+ if (!header.empty()) {
+ header = wrk.FileSys().RealPath(header);
+ }
+ return header;
+}
+
+bool cmQtAutoGeneratorMocUic::JobParseT::ParseUic(WorkerT& wrk,
+ MetaT const& meta)
+{
+ bool success = true;
+ if (meta.Content.find("ui_") != std::string::npos) {
+ const char* contentChars = meta.Content.c_str();
+ cmsys::RegularExpressionMatch match;
+ while (wrk.Uic().RegExpInclude.find(contentChars, match)) {
+ if (!ParseUicInclude(wrk, meta, match.match(1))) {
+ success = false;
+ break;
+ }
+ contentChars += match.end();
+ }
+ }
+ return success;
+}
+
+bool cmQtAutoGeneratorMocUic::JobParseT::ParseUicInclude(
+ WorkerT& wrk, MetaT const& meta, std::string&& includeString)
+{
+ bool success = false;
+ std::string uiInputFile = UicFindIncludedFile(wrk, meta, includeString);
+ if (!uiInputFile.empty()) {
+ if (!wrk.Uic().skipped(uiInputFile)) {
+ JobHandleT jobHandle(new JobUicT(std::move(uiInputFile), FileName,
+ std::move(includeString)));
+ success = wrk.Gen().ParallelJobPushUic(jobHandle);
+ } else {
+ // A skipped file is successful
+ success = true;
+ }
+ }
+ return success;
+}
+
+std::string cmQtAutoGeneratorMocUic::JobParseT::UicFindIncludedFile(
+ WorkerT& wrk, MetaT const& meta, std::string const& includeString)
+{
+ std::string res;
+ std::string searchFile =
+ cmSystemTools::GetFilenameWithoutLastExtension(includeString).substr(3);
+ searchFile += ".ui";
+ // Collect search paths list
+ std::deque<std::string> testFiles;
+ {
+ std::string const searchPath = SubDirPrefix(includeString);
+
+ std::string searchFileFull;
+ if (!searchPath.empty()) {
+ searchFileFull = searchPath;
+ searchFileFull += searchFile;
+ }
+ // Vicinity of the source
+ {
+ std::string const sourcePath = meta.FileDir;
+ testFiles.push_back(sourcePath + searchFile);
+ if (!searchPath.empty()) {
+ testFiles.push_back(sourcePath + searchFileFull);
+ }
+ }
+ // AUTOUIC search paths
+ if (!wrk.Uic().SearchPaths.empty()) {
+ for (std::string const& sPath : wrk.Uic().SearchPaths) {
+ testFiles.push_back((sPath + "/").append(searchFile));
+ }
+ if (!searchPath.empty()) {
+ for (std::string const& sPath : wrk.Uic().SearchPaths) {
+ testFiles.push_back((sPath + "/").append(searchFileFull));
+ }
+ }
+ }
+ }
+
+ // Search for the .ui file!
+ for (std::string const& testFile : testFiles) {
+ if (wrk.FileSys().FileExists(testFile)) {
+ res = wrk.FileSys().RealPath(testFile);
+ break;
+ }
+ }
+
+ // Log error
+ if (res.empty()) {
+ std::string emsg = "Could not find ";
+ emsg += Quoted(searchFile);
+ emsg += " in\n";
+ for (std::string const& testFile : testFiles) {
+ emsg += " ";
+ emsg += Quoted(testFile);
+ emsg += "\n";
+ }
+ wrk.LogFileError(GeneratorT::UIC, FileName, emsg);
+ }
+
+ return res;
+}
+
+void cmQtAutoGeneratorMocUic::JobMocPredefsT::Process(WorkerT& wrk)
+{
+ // (Re)generate moc_predefs.h on demand
+ bool generate(false);
+ bool fileExists(wrk.FileSys().FileExists(wrk.Moc().PredefsFileAbs));
+ if (!fileExists) {
+ if (wrk.Log().Verbose()) {
+ std::string reason = "Generating ";
+ reason += Quoted(wrk.Moc().PredefsFileRel);
+ reason += " because it doesn't exist";
+ wrk.LogInfo(GeneratorT::MOC, reason);
+ }
+ generate = true;
+ } else if (wrk.Moc().SettingsChanged) {
+ if (wrk.Log().Verbose()) {
+ std::string reason = "Generating ";
+ reason += Quoted(wrk.Moc().PredefsFileRel);
+ reason += " because the settings changed.";
+ wrk.LogInfo(GeneratorT::MOC, reason);
+ }
+ generate = true;
+ }
+ if (generate) {
+ ProcessResultT result;
+ {
+ // Compose command
+ std::vector<std::string> cmd = wrk.Moc().PredefsCmd;
+ // Add includes
+ cmd.insert(cmd.end(), wrk.Moc().Includes.begin(),
+ wrk.Moc().Includes.end());
+ // Add definitions
+ for (std::string const& def : wrk.Moc().Definitions) {
+ cmd.push_back("-D" + def);
+ }
+ // Execute command
+ if (!wrk.RunProcess(GeneratorT::MOC, result, cmd)) {
+ std::string emsg = "The content generation command for ";
+ emsg += Quoted(wrk.Moc().PredefsFileRel);
+ emsg += " failed.\n";
+ emsg += result.ErrorMessage;
+ wrk.LogCommandError(GeneratorT::MOC, emsg, cmd, result.StdOut);
+ }
+ }
+
+ // (Re)write predefs file only on demand
+ if (!result.error()) {
+ if (!fileExists ||
+ wrk.FileSys().FileDiffers(wrk.Moc().PredefsFileAbs, result.StdOut)) {
+ if (wrk.FileSys().FileWrite(GeneratorT::MOC, wrk.Moc().PredefsFileAbs,
+ result.StdOut)) {
+ // Success
+ } else {
+ std::string emsg = "Writing ";
+ emsg += Quoted(wrk.Moc().PredefsFileRel);
+ emsg += " failed.";
+ wrk.LogFileError(GeneratorT::MOC, wrk.Moc().PredefsFileAbs, emsg);
+ }
+ } else {
+ // Touch to update the time stamp
+ if (wrk.Log().Verbose()) {
+ std::string msg = "Touching ";
+ msg += Quoted(wrk.Moc().PredefsFileRel);
+ msg += ".";
+ wrk.LogInfo(GeneratorT::MOC, msg);
+ }
+ wrk.FileSys().Touch(wrk.Moc().PredefsFileAbs);
+ }
+ }
+ }
+}
+
+void cmQtAutoGeneratorMocUic::JobMocT::FindDependencies(
+ WorkerT& wrk, std::string const& content)
+{
+ wrk.Moc().FindDependencies(content, Depends);
+ DependsValid = true;
+}
+
+void cmQtAutoGeneratorMocUic::JobMocT::Process(WorkerT& wrk)
+{
+ // Compute build file name
+ if (!IncludeString.empty()) {
+ BuildFile = wrk.Base().AutogenIncludeDirAbs;
+ BuildFile += IncludeString;
+ } else {
+ std::string buildRel = wrk.Base().FilePathChecksum.getPart(SourceFile);
+ buildRel += '/';
+ buildRel += "moc_";
+ buildRel += cmSystemTools::GetFilenameWithoutLastExtension(SourceFile);
+ if (wrk.Base().MultiConfig != MultiConfigT::SINGLE) {
+ buildRel += wrk.Base().ConfigSuffix;
+ }
+ buildRel += ".cpp";
+ wrk.Gen().ParallelMocAutoRegister(buildRel);
+ BuildFile = wrk.Base().AbsoluteBuildPath(buildRel);
+ }
+
+ if (UpdateRequired(wrk)) {
+ GenerateMoc(wrk);
+ }
+}
+
+bool cmQtAutoGeneratorMocUic::JobMocT::UpdateRequired(WorkerT& wrk)
+{
+ bool const verbose = wrk.Gen().Log().Verbose();
+
+ // Test if the build file exists
+ if (!wrk.FileSys().FileExists(BuildFile)) {
+ if (verbose) {
+ std::string reason = "Generating ";
+ reason += Quoted(BuildFile);
+ reason += " from its source file ";
+ reason += Quoted(SourceFile);
+ reason += " because it doesn't exist";
+ wrk.LogInfo(GeneratorT::MOC, reason);
+ }
+ return true;
+ }
+
+ // Test if any setting changed
+ if (wrk.Moc().SettingsChanged) {
+ if (verbose) {
+ std::string reason = "Generating ";
+ reason += Quoted(BuildFile);
+ reason += " from ";
+ reason += Quoted(SourceFile);
+ reason += " because the MOC settings changed";
+ wrk.LogInfo(GeneratorT::MOC, reason);
+ }
+ return true;
+ }
+
+ // Test if the moc_predefs file is newer
+ if (!wrk.Moc().PredefsFileAbs.empty()) {
+ bool isOlder = false;
+ {
+ std::string error;
+ isOlder = wrk.FileSys().FileIsOlderThan(
+ BuildFile, wrk.Moc().PredefsFileAbs, &error);
+ if (!isOlder && !error.empty()) {
+ wrk.LogError(GeneratorT::MOC, error);
+ return false;
+ }
+ }
+ if (isOlder) {
+ if (verbose) {
+ std::string reason = "Generating ";
+ reason += Quoted(BuildFile);
+ reason += " because it's older than: ";
+ reason += Quoted(wrk.Moc().PredefsFileAbs);
+ wrk.LogInfo(GeneratorT::MOC, reason);
+ }
+ return true;
+ }
+ }
+
+ // Test if the source file is newer
+ {
+ bool isOlder = false;
+ {
+ std::string error;
+ isOlder = wrk.FileSys().FileIsOlderThan(BuildFile, SourceFile, &error);
+ if (!isOlder && !error.empty()) {
+ wrk.LogError(GeneratorT::MOC, error);
+ return false;
+ }
+ }
+ if (isOlder) {
+ if (verbose) {
+ std::string reason = "Generating ";
+ reason += Quoted(BuildFile);
+ reason += " because it's older than its source file ";
+ reason += Quoted(SourceFile);
+ wrk.LogInfo(GeneratorT::MOC, reason);
+ }
+ return true;
+ }
+ }
+
+ // Test if a dependency file is newer
+ {
+ // Read dependencies on demand
+ if (!DependsValid) {
+ std::string content;
+ {
+ std::string error;
+ if (!wrk.FileSys().FileRead(content, SourceFile, &error)) {
+ std::string emsg = "Could not read file\n ";
+ emsg += Quoted(SourceFile);
+ emsg += "\nrequired by moc include ";
+ emsg += Quoted(IncludeString);
+ emsg += " in\n ";
+ emsg += Quoted(IncluderFile);
+ emsg += ".\n";
+ emsg += error;
+ wrk.LogError(GeneratorT::MOC, emsg);
+ return false;
+ }
+ }
+ FindDependencies(wrk, content);
+ }
+ // Check dependency timestamps
+ std::string error;
+ std::string sourceDir = SubDirPrefix(SourceFile);
+ for (std::string const& depFileRel : Depends) {
+ std::string depFileAbs =
+ wrk.Moc().FindIncludedFile(sourceDir, depFileRel);
+ if (!depFileAbs.empty()) {
+ if (wrk.FileSys().FileIsOlderThan(BuildFile, depFileAbs, &error)) {
+ if (verbose) {
+ std::string reason = "Generating ";
+ reason += Quoted(BuildFile);
+ reason += " from ";
+ reason += Quoted(SourceFile);
+ reason += " because it is older than it's dependency file ";
+ reason += Quoted(depFileAbs);
+ wrk.LogInfo(GeneratorT::MOC, reason);
+ }
+ return true;
+ }
+ if (!error.empty()) {
+ wrk.LogError(GeneratorT::MOC, error);
+ return false;
+ }
+ } else {
+ std::string message = "Could not find dependency file ";
+ message += Quoted(depFileRel);
+ wrk.LogFileWarning(GeneratorT::MOC, SourceFile, message);
+ }
+ }
+ }
+
+ return false;
+}
+
+void cmQtAutoGeneratorMocUic::JobMocT::GenerateMoc(WorkerT& wrk)
+{
+ // Make sure the parent directory exists
+ if (wrk.FileSys().MakeParentDirectory(GeneratorT::MOC, BuildFile)) {
+ // Compose moc command
+ std::vector<std::string> cmd;
+ cmd.push_back(wrk.Moc().Executable);
+ // Add options
+ cmd.insert(cmd.end(), wrk.Moc().AllOptions.begin(),
+ wrk.Moc().AllOptions.end());
+ // Add predefs include
+ if (!wrk.Moc().PredefsFileAbs.empty()) {
+ cmd.push_back("--include");
+ cmd.push_back(wrk.Moc().PredefsFileAbs);
+ }
+ cmd.push_back("-o");
+ cmd.push_back(BuildFile);
+ cmd.push_back(SourceFile);
+
+ // Execute moc command
+ ProcessResultT result;
+ if (wrk.RunProcess(GeneratorT::MOC, result, cmd)) {
+ // Moc command success
+ if (IncludeString.empty()) {
+ // Notify the generator that a not included file changed
+ wrk.Gen().ParallelMocAutoUpdated();
+ }
+ } else {
+ // Moc command failed
+ {
+ std::string emsg = "The moc process failed to compile\n ";
+ emsg += Quoted(SourceFile);
+ emsg += "\ninto\n ";
+ emsg += Quoted(BuildFile);
+ emsg += ".\n";
+ emsg += result.ErrorMessage;
+ wrk.LogCommandError(GeneratorT::MOC, emsg, cmd, result.StdOut);
+ }
+ wrk.FileSys().FileRemove(BuildFile);
+ }
+ }
+}
+
+void cmQtAutoGeneratorMocUic::JobUicT::Process(WorkerT& wrk)
+{
+ // Compute build file name
+ BuildFile = wrk.Base().AutogenIncludeDirAbs;
+ BuildFile += IncludeString;
+
+ if (UpdateRequired(wrk)) {
+ GenerateUic(wrk);
+ }
+}
+
+bool cmQtAutoGeneratorMocUic::JobUicT::UpdateRequired(WorkerT& wrk)
+{
+ bool const verbose = wrk.Gen().Log().Verbose();
+
+ // Test if the build file exists
+ if (!wrk.FileSys().FileExists(BuildFile)) {
+ if (verbose) {
+ std::string reason = "Generating ";
+ reason += Quoted(BuildFile);
+ reason += " from its source file ";
+ reason += Quoted(SourceFile);
+ reason += " because it doesn't exist";
+ wrk.LogInfo(GeneratorT::UIC, reason);
+ }
+ return true;
+ }
+
+ // Test if the uic settings changed
+ if (wrk.Uic().SettingsChanged) {
+ if (verbose) {
+ std::string reason = "Generating ";
+ reason += Quoted(BuildFile);
+ reason += " from ";
+ reason += Quoted(SourceFile);
+ reason += " because the UIC settings changed";
+ wrk.LogInfo(GeneratorT::UIC, reason);
+ }
+ return true;
+ }
+
+ // Test if the source file is newer
+ {
+ bool isOlder = false;
+ {
+ std::string error;
+ isOlder = wrk.FileSys().FileIsOlderThan(BuildFile, SourceFile, &error);
+ if (!isOlder && !error.empty()) {
+ wrk.LogError(GeneratorT::UIC, error);
+ return false;
+ }
+ }
+ if (isOlder) {
+ if (verbose) {
+ std::string reason = "Generating ";
+ reason += Quoted(BuildFile);
+ reason += " because it's older than its source file ";
+ reason += Quoted(SourceFile);
+ wrk.LogInfo(GeneratorT::UIC, reason);
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void cmQtAutoGeneratorMocUic::JobUicT::GenerateUic(WorkerT& wrk)
+{
+ // Make sure the parent directory exists
+ if (wrk.FileSys().MakeParentDirectory(GeneratorT::UIC, BuildFile)) {
+ // Compose uic command
+ std::vector<std::string> cmd;
+ cmd.push_back(wrk.Uic().Executable);
+ {
+ std::vector<std::string> allOpts = wrk.Uic().TargetOptions;
+ auto optionIt = wrk.Uic().Options.find(SourceFile);
+ if (optionIt != wrk.Uic().Options.end()) {
+ UicMergeOptions(allOpts, optionIt->second,
+ (wrk.Base().QtVersionMajor == 5));
+ }
+ cmd.insert(cmd.end(), allOpts.begin(), allOpts.end());
+ }
+ cmd.push_back("-o");
+ cmd.push_back(BuildFile);
+ cmd.push_back(SourceFile);
+
+ ProcessResultT result;
+ if (wrk.RunProcess(GeneratorT::UIC, result, cmd)) {
+ // Success
+ } else {
+ // Command failed
+ {
+ std::string emsg = "The uic process failed to compile\n ";
+ emsg += Quoted(SourceFile);
+ emsg += "\ninto\n ";
+ emsg += Quoted(BuildFile);
+ emsg += "\nincluded by\n ";
+ emsg += Quoted(IncluderFile);
+ emsg += ".\n";
+ emsg += result.ErrorMessage;
+ wrk.LogCommandError(GeneratorT::UIC, emsg, cmd, result.StdOut);
+ }
+ wrk.FileSys().FileRemove(BuildFile);
+ }
+ }
+}
+
+void cmQtAutoGeneratorMocUic::JobDeleterT::operator()(JobT* job)
+{
+ delete job;
+}
+
+cmQtAutoGeneratorMocUic::WorkerT::WorkerT(cmQtAutoGeneratorMocUic* gen,
+ uv_loop_t* uvLoop)
+ : Gen_(gen)
+{
+ // Initialize uv asynchronous callback for process starting
+ ProcessRequest_.init(*uvLoop, &WorkerT::UVProcessStart, this);
+ // Start thread
+ Thread_ = std::thread(&WorkerT::Loop, this);
+}
+
+cmQtAutoGeneratorMocUic::WorkerT::~WorkerT()
+{
+ // Join thread
+ if (Thread_.joinable()) {
+ Thread_.join();
+ }
+}
+
+void cmQtAutoGeneratorMocUic::WorkerT::LogInfo(
+ GeneratorT genType, std::string const& message) const
+{
+ return Log().Info(genType, message);
+}
+
+void cmQtAutoGeneratorMocUic::WorkerT::LogWarning(
+ GeneratorT genType, std::string const& message) const
+{
+ return Log().Warning(genType, message);
+}
+
+void cmQtAutoGeneratorMocUic::WorkerT::LogFileWarning(
+ GeneratorT genType, std::string const& filename,
+ std::string const& message) const
+{
+ return Log().WarningFile(genType, filename, message);
+}
+
+void cmQtAutoGeneratorMocUic::WorkerT::LogError(
+ GeneratorT genType, std::string const& message) const
+{
+ Gen().ParallelRegisterJobError();
+ Log().Error(genType, message);
+}
+
+void cmQtAutoGeneratorMocUic::WorkerT::LogFileError(
+ GeneratorT genType, std::string const& filename,
+ std::string const& message) const
+{
+ Gen().ParallelRegisterJobError();
+ Log().ErrorFile(genType, filename, message);
+}
+
+void cmQtAutoGeneratorMocUic::WorkerT::LogCommandError(
+ GeneratorT genType, std::string const& message,
+ std::vector<std::string> const& command, std::string const& output) const
+{
+ Gen().ParallelRegisterJobError();
+ Log().ErrorCommand(genType, message, command, output);
+}
+
+bool cmQtAutoGeneratorMocUic::WorkerT::RunProcess(
+ GeneratorT genType, ProcessResultT& result,
+ std::vector<std::string> const& command)
+{
+ if (command.empty()) {
+ return false;
+ }
+
+ // Create process instance
+ {
+ std::lock_guard<std::mutex> lock(ProcessMutex_);
+ Process_ = cm::make_unique<ReadOnlyProcessT>();
+ Process_->setup(&result, true, command, Gen().Base().AutogenBuildDir);
+ }
+
+ // Send asynchronous process start request to libuv loop
+ ProcessRequest_.send();
+
+ // Log command
+ if (this->Log().Verbose()) {
+ std::string msg = "Running command:\n";
+ msg += QuotedCommand(command);
+ msg += '\n';
+ this->LogInfo(genType, msg);
+ }
+
+ // Wait until the process has been finished and destroyed
+ {
+ std::unique_lock<std::mutex> ulock(ProcessMutex_);
+ while (Process_) {
+ ProcessCondition_.wait(ulock);
+ }
+ }
+ return !result.error();
+}
+
+void cmQtAutoGeneratorMocUic::WorkerT::Loop()
+{
+ while (true) {
+ Gen().WorkerSwapJob(JobHandle_);
+ if (JobHandle_) {
+ JobHandle_->Process(*this);
+ } else {
+ break;
+ }
+ }
+}
+
+void cmQtAutoGeneratorMocUic::WorkerT::UVProcessStart(uv_async_t* handle)
+{
+ auto& wrk = *reinterpret_cast<WorkerT*>(handle->data);
+ {
+ std::lock_guard<std::mutex> lock(wrk.ProcessMutex_);
+ if (wrk.Process_ && !wrk.Process_->IsStarted()) {
+ wrk.Process_->start(handle->loop,
+ std::bind(&WorkerT::UVProcessFinished, &wrk));
+ }
+ }
+}
+
+void cmQtAutoGeneratorMocUic::WorkerT::UVProcessFinished()
+{
+ {
+ std::lock_guard<std::mutex> lock(ProcessMutex_);
+ if (Process_ && Process_->IsFinished()) {
+ Process_.reset();
+ }
+ }
+ // Notify idling thread
+ ProcessCondition_.notify_one();
+}
cmQtAutoGeneratorMocUic::cmQtAutoGeneratorMocUic()
- : MultiConfig(cmQtAutoGen::WRAP)
- , IncludeProjectDirsBefore(false)
- , QtVersionMajor(4)
- , MocSettingsChanged(false)
- , MocPredefsChanged(false)
- , MocRelaxedMode(false)
- , UicSettingsChanged(false)
+ : Base_(&FileSys())
+ , Moc_(&FileSys())
+ , Stage_(StageT::SETTINGS_READ)
+ , JobsRemain_(0)
+ , JobError_(false)
+ , JobThreadsAbort_(false)
+ , MocAutoFileUpdated_(false)
{
// Precompile regular expressions
- this->MocRegExpInclude.compile(
+ Moc_.RegExpInclude.compile(
"[\n][ \t]*#[ \t]*include[ \t]+"
"[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
- this->UicRegExpInclude.compile("[\n][ \t]*#[ \t]*include[ \t]+"
- "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
+ Uic_.RegExpInclude.compile("[\n][ \t]*#[ \t]*include[ \t]+"
+ "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
+
+ // Initialize libuv asynchronous iteration request
+ UVRequest().init(*UVLoop(), &cmQtAutoGeneratorMocUic::UVPollStage, this);
}
-bool cmQtAutoGeneratorMocUic::InitInfoFile(cmMakefile* makefile)
+cmQtAutoGeneratorMocUic::~cmQtAutoGeneratorMocUic()
+{
+}
+
+bool cmQtAutoGeneratorMocUic::Init(cmMakefile* makefile)
{
// -- Meta
- this->HeaderExtensions = makefile->GetCMakeInstance()->GetHeaderExtensions();
+ Base_.HeaderExtensions = makefile->GetCMakeInstance()->GetHeaderExtensions();
// Utility lambdas
auto InfoGet = [makefile](const char* key) {
@@ -87,7 +1161,7 @@ bool cmQtAutoGeneratorMocUic::InitInfoFile(cmMakefile* makefile)
std::string const value = makefile->GetSafeDefinition(key);
std::string::size_type pos = 0;
while (pos < value.size()) {
- std::string::size_type next = value.find(cmQtAutoGen::listSep, pos);
+ std::string::size_type next = value.find(ListSep, pos);
std::string::size_type length =
(next != std::string::npos) ? next - pos : value.size() - pos;
// Remove enclosing braces
@@ -102,7 +1176,7 @@ bool cmQtAutoGeneratorMocUic::InitInfoFile(cmMakefile* makefile)
}
}
pos += length;
- pos += cmQtAutoGen::listSep.size();
+ pos += ListSep.size();
}
}
return lists;
@@ -112,7 +1186,7 @@ bool cmQtAutoGeneratorMocUic::InitInfoFile(cmMakefile* makefile)
{
std::string keyConf = key;
keyConf += '_';
- keyConf += this->GetInfoConfig();
+ keyConf += InfoConfig();
valueConf = makefile->GetDefinition(keyConf);
}
if (valueConf == nullptr) {
@@ -128,122 +1202,177 @@ bool cmQtAutoGeneratorMocUic::InitInfoFile(cmMakefile* makefile)
};
// -- Read info file
- if (!makefile->ReadListFile(this->GetInfoFile().c_str())) {
- this->LogFileError(cmQtAutoGen::GEN, this->GetInfoFile(),
- "File processing failed");
+ if (!makefile->ReadListFile(InfoFile().c_str())) {
+ Log().ErrorFile(GeneratorT::GEN, InfoFile(), "File processing failed");
return false;
}
// -- Meta
- this->MultiConfig = cmQtAutoGen::MultiConfigType(InfoGet("AM_MULTI_CONFIG"));
- this->ConfigSuffix = InfoGetConfig("AM_CONFIG_SUFFIX");
- if (this->ConfigSuffix.empty()) {
- this->ConfigSuffix = "_";
- this->ConfigSuffix += this->GetInfoConfig();
+ Base_.MultiConfig = MultiConfigType(InfoGet("AM_MULTI_CONFIG"));
+
+ Base_.ConfigSuffix = InfoGetConfig("AM_CONFIG_SUFFIX");
+ if (Base_.ConfigSuffix.empty()) {
+ Base_.ConfigSuffix = "_";
+ Base_.ConfigSuffix += InfoConfig();
}
- this->SettingsFile = InfoGetConfig("AM_SETTINGS_FILE");
- if (this->SettingsFile.empty()) {
- this->LogFileError(cmQtAutoGen::GEN, this->GetInfoFile(),
- "Settings file name missing");
+ SettingsFile_ = InfoGetConfig("AM_SETTINGS_FILE");
+ if (SettingsFile_.empty()) {
+ Log().ErrorFile(GeneratorT::GEN, InfoFile(), "Settings file name missing");
return false;
}
+ {
+ unsigned long num = Base_.NumThreads;
+ if (cmSystemTools::StringToULong(InfoGet("AM_PARALLEL"), &num)) {
+ num = std::max<unsigned long>(num, 1);
+ num = std::min<unsigned long>(num, ParallelMax);
+ Base_.NumThreads = static_cast<unsigned int>(num);
+ }
+ }
+
// - Files and directories
- this->ProjectSourceDir = InfoGet("AM_CMAKE_SOURCE_DIR");
- this->ProjectBinaryDir = InfoGet("AM_CMAKE_BINARY_DIR");
- this->CurrentSourceDir = InfoGet("AM_CMAKE_CURRENT_SOURCE_DIR");
- this->CurrentBinaryDir = InfoGet("AM_CMAKE_CURRENT_BINARY_DIR");
- this->IncludeProjectDirsBefore =
+ Base_.ProjectSourceDir = InfoGet("AM_CMAKE_SOURCE_DIR");
+ Base_.ProjectBinaryDir = InfoGet("AM_CMAKE_BINARY_DIR");
+ Base_.CurrentSourceDir = InfoGet("AM_CMAKE_CURRENT_SOURCE_DIR");
+ Base_.CurrentBinaryDir = InfoGet("AM_CMAKE_CURRENT_BINARY_DIR");
+ Base_.IncludeProjectDirsBefore =
InfoGetBool("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
- this->AutogenBuildDir = InfoGet("AM_BUILD_DIR");
- if (this->AutogenBuildDir.empty()) {
- this->LogFileError(cmQtAutoGen::GEN, this->GetInfoFile(),
- "Autogen build directory missing");
+ Base_.AutogenBuildDir = InfoGet("AM_BUILD_DIR");
+ if (Base_.AutogenBuildDir.empty()) {
+ Log().ErrorFile(GeneratorT::GEN, InfoFile(),
+ "Autogen build directory missing");
return false;
}
// - Qt environment
- if (!cmSystemTools::StringToULong(InfoGet("AM_QT_VERSION_MAJOR"),
- &this->QtVersionMajor)) {
- this->QtVersionMajor = 4;
+ {
+ unsigned long qtv = Base_.QtVersionMajor;
+ if (cmSystemTools::StringToULong(InfoGet("AM_QT_VERSION_MAJOR"), &qtv)) {
+ Base_.QtVersionMajor = static_cast<unsigned int>(qtv);
+ }
}
- this->MocExecutable = InfoGet("AM_QT_MOC_EXECUTABLE");
- this->UicExecutable = InfoGet("AM_QT_UIC_EXECUTABLE");
// - Moc
- if (this->MocEnabled()) {
- this->MocSkipList = InfoGetList("AM_MOC_SKIP");
- this->MocDefinitions = InfoGetConfigList("AM_MOC_DEFINITIONS");
+ Moc_.Executable = InfoGet("AM_QT_MOC_EXECUTABLE");
+ Moc_.Enabled = !Moc().Executable.empty();
+ if (Moc().Enabled) {
+ {
+ auto lst = InfoGetList("AM_MOC_SKIP");
+ Moc_.SkipList.insert(lst.begin(), lst.end());
+ }
+ Moc_.Definitions = InfoGetConfigList("AM_MOC_DEFINITIONS");
#ifdef _WIN32
{
- std::string const win32("WIN32");
- if (!ListContains(this->MocDefinitions, win32)) {
- this->MocDefinitions.push_back(win32);
+ std::string win32("WIN32");
+ auto itB = Moc().Definitions.cbegin();
+ auto itE = Moc().Definitions.cend();
+ if (std::find(itB, itE, win32) == itE) {
+ Moc_.Definitions.emplace_back(std::move(win32));
}
}
#endif
- this->MocIncludePaths = InfoGetConfigList("AM_MOC_INCLUDES");
- this->MocOptions = InfoGetList("AM_MOC_OPTIONS");
- this->MocRelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE");
- {
- std::vector<std::string> const MocMacroNames =
- InfoGetList("AM_MOC_MACRO_NAMES");
- for (std::string const& item : MocMacroNames) {
- this->MocMacroFilters.emplace_back(
- item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]"));
- }
+ Moc_.IncludePaths = InfoGetConfigList("AM_MOC_INCLUDES");
+ Moc_.Options = InfoGetList("AM_MOC_OPTIONS");
+ Moc_.RelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE");
+ for (std::string const& item : InfoGetList("AM_MOC_MACRO_NAMES")) {
+ Moc_.MacroFilters.emplace_back(
+ item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]"));
}
{
- std::vector<std::string> const mocDependFilters =
- InfoGetList("AM_MOC_DEPEND_FILTERS");
- // Insert Q_PLUGIN_METADATA dependency filter
- if (this->QtVersionMajor != 4) {
- this->MocDependFilterPush("Q_PLUGIN_METADATA",
- "[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\("
- "[^\\)]*FILE[ \t]*\"([^\"]+)\"");
+ auto pushFilter = [this](std::string const& key, std::string const& exp,
+ std::string& error) {
+ if (!key.empty()) {
+ if (!exp.empty()) {
+ Moc_.DependFilters.push_back(KeyExpT());
+ KeyExpT& filter(Moc_.DependFilters.back());
+ if (filter.Exp.compile(exp)) {
+ filter.Key = key;
+ } else {
+ error = "Regular expression compiling failed";
+ }
+ } else {
+ error = "Regular expression is empty";
+ }
+ } else {
+ error = "Key is empty";
+ }
+ if (!error.empty()) {
+ error = ("AUTOMOC_DEPEND_FILTERS: " + error);
+ error += "\n";
+ error += " Key: ";
+ error += Quoted(key);
+ error += "\n";
+ error += " Exp: ";
+ error += Quoted(exp);
+ error += "\n";
+ }
+ };
+
+ std::string error;
+ // Insert default filter for Q_PLUGIN_METADATA
+ if (Base().QtVersionMajor != 4) {
+ pushFilter("Q_PLUGIN_METADATA", "[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\("
+ "[^\\)]*FILE[ \t]*\"([^\"]+)\"",
+ error);
}
// Insert user defined dependency filters
- if ((mocDependFilters.size() % 2) == 0) {
- for (std::vector<std::string>::const_iterator
- dit = mocDependFilters.begin(),
- ditEnd = mocDependFilters.end();
- dit != ditEnd; dit += 2) {
- if (!this->MocDependFilterPush(*dit, *(dit + 1))) {
- return false;
+ {
+ std::vector<std::string> flts = InfoGetList("AM_MOC_DEPEND_FILTERS");
+ if ((flts.size() % 2) == 0) {
+ for (std::vector<std::string>::iterator itC = flts.begin(),
+ itE = flts.end();
+ itC != itE; itC += 2) {
+ pushFilter(*itC, *(itC + 1), error);
+ if (!error.empty()) {
+ break;
+ }
}
+ } else {
+ Log().ErrorFile(
+ GeneratorT::MOC, InfoFile(),
+ "AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2");
+ return false;
}
- } else {
- this->LogFileError(
- cmQtAutoGen::MOC, this->GetInfoFile(),
- "AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2");
+ }
+ if (!error.empty()) {
+ Log().ErrorFile(GeneratorT::MOC, InfoFile(), error);
return false;
}
}
- this->MocPredefsCmd = InfoGetList("AM_MOC_PREDEFS_CMD");
+ Moc_.PredefsCmd = InfoGetList("AM_MOC_PREDEFS_CMD");
+ // Install moc predefs job
+ if (!Moc().PredefsCmd.empty()) {
+ JobQueues_.MocPredefs.emplace_back(new JobMocPredefsT());
+ }
}
// - Uic
- if (this->UicEnabled()) {
- this->UicSkipList = InfoGetList("AM_UIC_SKIP");
- this->UicSearchPaths = InfoGetList("AM_UIC_SEARCH_PATHS");
- this->UicTargetOptions = InfoGetConfigList("AM_UIC_TARGET_OPTIONS");
+ Uic_.Executable = InfoGet("AM_QT_UIC_EXECUTABLE");
+ Uic_.Enabled = !Uic().Executable.empty();
+ if (Uic().Enabled) {
+ {
+ auto lst = InfoGetList("AM_UIC_SKIP");
+ Uic_.SkipList.insert(lst.begin(), lst.end());
+ }
+ Uic_.SearchPaths = InfoGetList("AM_UIC_SEARCH_PATHS");
+ Uic_.TargetOptions = InfoGetConfigList("AM_UIC_TARGET_OPTIONS");
{
auto sources = InfoGetList("AM_UIC_OPTIONS_FILES");
auto options = InfoGetLists("AM_UIC_OPTIONS_OPTIONS");
// Compare list sizes
if (sources.size() != options.size()) {
std::ostringstream ost;
- ost << "files/options lists sizes mismatch (" << sources.size() << "/"
+ ost << "files/options lists sizes missmatch (" << sources.size() << "/"
<< options.size() << ")";
- this->LogFileError(cmQtAutoGen::UIC, this->GetInfoFile(), ost.str());
+ Log().ErrorFile(GeneratorT::UIC, InfoFile(), ost.str());
return false;
}
auto fitEnd = sources.cend();
auto fit = sources.begin();
auto oit = options.begin();
while (fit != fitEnd) {
- this->UicOptions[*fit] = std::move(*oit);
+ Uic_.Options[*fit] = std::move(*oit);
++fit;
++oit;
}
@@ -252,54 +1381,51 @@ bool cmQtAutoGeneratorMocUic::InitInfoFile(cmMakefile* makefile)
// Initialize source file jobs
{
- // Utility lambdas
- auto AddJob = [this](std::map<std::string, SourceJob>& jobs,
- std::string&& sourceFile) {
- const bool moc = !this->MocSkip(sourceFile);
- const bool uic = !this->UicSkip(sourceFile);
- if (moc || uic) {
- SourceJob& job = jobs[std::move(sourceFile)];
- job.Moc = moc;
- job.Uic = uic;
- }
- };
+ std::hash<std::string> stringHash;
+ std::set<std::size_t> uniqueHeaders;
// Add header jobs
for (std::string& hdr : InfoGetList("AM_HEADERS")) {
- AddJob(this->HeaderJobs, std::move(hdr));
+ const bool moc = !Moc().skipped(hdr);
+ const bool uic = !Uic().skipped(hdr);
+ if ((moc || uic) && uniqueHeaders.emplace(stringHash(hdr)).second) {
+ JobQueues_.Headers.emplace_back(
+ new JobParseT(std::move(hdr), moc, uic, true));
+ }
}
// Add source jobs
{
std::vector<std::string> sources = InfoGetList("AM_SOURCES");
// Add header(s) for the source file
- for (std::string const& src : sources) {
- const bool srcMoc = !this->MocSkip(src);
- const bool srcUic = !this->UicSkip(src);
+ for (std::string& src : sources) {
+ const bool srcMoc = !Moc().skipped(src);
+ const bool srcUic = !Uic().skipped(src);
if (!srcMoc && !srcUic) {
continue;
}
// Search for the default header file and a private header
- std::array<std::string, 2> headerBases;
- headerBases[0] = SubDirPrefix(src);
- headerBases[0] += cmSystemTools::GetFilenameWithoutLastExtension(src);
- headerBases[1] = headerBases[0];
- headerBases[1] += "_p";
- for (std::string const& headerBase : headerBases) {
- std::string header;
- if (this->FindHeader(header, headerBase)) {
- const bool moc = srcMoc && !this->MocSkip(header);
- const bool uic = srcUic && !this->UicSkip(header);
- if (moc || uic) {
- SourceJob& job = this->HeaderJobs[std::move(header)];
- job.Moc = moc;
- job.Uic = uic;
+ {
+ std::array<std::string, 2> bases;
+ bases[0] = SubDirPrefix(src);
+ bases[0] += cmSystemTools::GetFilenameWithoutLastExtension(src);
+ bases[1] = bases[0];
+ bases[1] += "_p";
+ for (std::string const& headerBase : bases) {
+ std::string header;
+ if (Base().FindHeader(header, headerBase)) {
+ const bool moc = srcMoc && !Moc().skipped(header);
+ const bool uic = srcUic && !Uic().skipped(header);
+ if ((moc || uic) &&
+ uniqueHeaders.emplace(stringHash(header)).second) {
+ JobQueues_.Headers.emplace_back(
+ new JobParseT(std::move(header), moc, uic, true));
+ }
}
}
}
- }
- // Add Source jobs
- for (std::string& src : sources) {
- AddJob(this->SourceJobs, std::move(src));
+ // Add source job
+ JobQueues_.Sources.emplace_back(
+ new JobParseT(std::move(src), srcMoc, srcUic));
}
}
}
@@ -308,58 +1434,58 @@ bool cmQtAutoGeneratorMocUic::InitInfoFile(cmMakefile* makefile)
// ------------------------
// Init file path checksum generator
- this->FilePathChecksum.setupParentDirs(
- this->CurrentSourceDir, this->CurrentBinaryDir, this->ProjectSourceDir,
- this->ProjectBinaryDir);
+ Base_.FilePathChecksum.setupParentDirs(
+ Base().CurrentSourceDir, Base().CurrentBinaryDir, Base().ProjectSourceDir,
+ Base().ProjectBinaryDir);
// include directory
- this->AutogenIncludeDir = "include";
- if (this->MultiConfig != cmQtAutoGen::SINGLE) {
- this->AutogenIncludeDir += this->ConfigSuffix;
+ Base_.AutogenIncludeDirRel = "include";
+ if (Base().MultiConfig != MultiConfigT::SINGLE) {
+ Base_.AutogenIncludeDirRel += Base().ConfigSuffix;
}
- this->AutogenIncludeDir += "/";
+ Base_.AutogenIncludeDirRel += "/";
+ Base_.AutogenIncludeDirAbs =
+ Base_.AbsoluteBuildPath(Base().AutogenIncludeDirRel);
// Moc variables
- if (this->MocEnabled()) {
+ if (Moc().Enabled) {
// Mocs compilation file
- this->MocCompFileRel = "mocs_compilation";
- if (this->MultiConfig == cmQtAutoGen::FULL) {
- this->MocCompFileRel += this->ConfigSuffix;
+ Moc_.CompFileRel = "mocs_compilation";
+ if (Base_.MultiConfig == MultiConfigT::MULTI) {
+ Moc_.CompFileRel += Base().ConfigSuffix;
}
- this->MocCompFileRel += ".cpp";
- this->MocCompFileAbs = cmSystemTools::CollapseCombinedPath(
- this->AutogenBuildDir, this->MocCompFileRel);
+ Moc_.CompFileRel += ".cpp";
+ Moc_.CompFileAbs = Base_.AbsoluteBuildPath(Moc().CompFileRel);
// Moc predefs file
- if (!this->MocPredefsCmd.empty()) {
- this->MocPredefsFileRel = "moc_predefs";
- if (this->MultiConfig != cmQtAutoGen::SINGLE) {
- this->MocPredefsFileRel += this->ConfigSuffix;
+ if (!Moc_.PredefsCmd.empty()) {
+ Moc_.PredefsFileRel = "moc_predefs";
+ if (Base_.MultiConfig != MultiConfigT::SINGLE) {
+ Moc_.PredefsFileRel += Base().ConfigSuffix;
}
- this->MocPredefsFileRel += ".h";
- this->MocPredefsFileAbs = cmSystemTools::CollapseCombinedPath(
- this->AutogenBuildDir, this->MocPredefsFileRel);
+ Moc_.PredefsFileRel += ".h";
+ Moc_.PredefsFileAbs = Base_.AbsoluteBuildPath(Moc().PredefsFileRel);
}
// Sort include directories on demand
- if (this->IncludeProjectDirsBefore) {
+ if (Base().IncludeProjectDirsBefore) {
// Move strings to temporary list
std::list<std::string> includes;
- includes.insert(includes.end(), this->MocIncludePaths.begin(),
- this->MocIncludePaths.end());
- this->MocIncludePaths.clear();
- this->MocIncludePaths.reserve(includes.size());
+ includes.insert(includes.end(), Moc().IncludePaths.begin(),
+ Moc().IncludePaths.end());
+ Moc_.IncludePaths.clear();
+ Moc_.IncludePaths.reserve(includes.size());
// Append project directories only
{
std::array<std::string const*, 2> const movePaths = {
- { &this->ProjectBinaryDir, &this->ProjectSourceDir }
+ { &Base().ProjectBinaryDir, &Base().ProjectSourceDir }
};
for (std::string const* ppath : movePaths) {
std::list<std::string>::iterator it = includes.begin();
while (it != includes.end()) {
std::string const& path = *it;
if (cmSystemTools::StringStartsWith(path, ppath->c_str())) {
- this->MocIncludePaths.push_back(path);
+ Moc_.IncludePaths.push_back(path);
it = includes.erase(it);
} else {
++it;
@@ -368,14 +1494,14 @@ bool cmQtAutoGeneratorMocUic::InitInfoFile(cmMakefile* makefile)
}
}
// Append remaining directories
- this->MocIncludePaths.insert(this->MocIncludePaths.end(),
- includes.begin(), includes.end());
+ Moc_.IncludePaths.insert(Moc_.IncludePaths.end(), includes.begin(),
+ includes.end());
}
// Compose moc includes list
{
std::set<std::string> frameworkPaths;
- for (std::string const& path : this->MocIncludePaths) {
- this->MocIncludes.push_back("-I" + path);
+ for (std::string const& path : Moc().IncludePaths) {
+ Moc_.Includes.push_back("-I" + path);
// Extract framework path
if (cmHasLiteralSuffix(path, ".framework/Headers")) {
// Go up twice to get to the framework root
@@ -388,1346 +1514,511 @@ bool cmQtAutoGeneratorMocUic::InitInfoFile(cmMakefile* makefile)
}
// Append framework includes
for (std::string const& path : frameworkPaths) {
- this->MocIncludes.push_back("-F");
- this->MocIncludes.push_back(path);
+ Moc_.Includes.push_back("-F");
+ Moc_.Includes.push_back(path);
}
}
// Setup single list with all options
{
// Add includes
- this->MocAllOptions.insert(this->MocAllOptions.end(),
- this->MocIncludes.begin(),
- this->MocIncludes.end());
+ Moc_.AllOptions.insert(Moc_.AllOptions.end(), Moc().Includes.begin(),
+ Moc().Includes.end());
// Add definitions
- for (std::string const& def : this->MocDefinitions) {
- this->MocAllOptions.push_back("-D" + def);
+ for (std::string const& def : Moc().Definitions) {
+ Moc_.AllOptions.push_back("-D" + def);
}
// Add options
- this->MocAllOptions.insert(this->MocAllOptions.end(),
- this->MocOptions.begin(),
- this->MocOptions.end());
+ Moc_.AllOptions.insert(Moc_.AllOptions.end(), Moc().Options.begin(),
+ Moc().Options.end());
}
}
return true;
}
-void cmQtAutoGeneratorMocUic::SettingsFileRead(cmMakefile* makefile)
+bool cmQtAutoGeneratorMocUic::Process()
+{
+ // Run libuv event loop
+ UVRequest().send();
+ if (uv_run(UVLoop(), UV_RUN_DEFAULT) == 0) {
+ if (JobError_) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ return true;
+}
+
+void cmQtAutoGeneratorMocUic::UVPollStage(uv_async_t* handle)
+{
+ reinterpret_cast<cmQtAutoGeneratorMocUic*>(handle->data)->PollStage();
+}
+
+void cmQtAutoGeneratorMocUic::PollStage()
+{
+ switch (Stage_) {
+ case StageT::SETTINGS_READ:
+ SettingsFileRead();
+ SetStage(StageT::CREATE_DIRECTORIES);
+ break;
+ case StageT::CREATE_DIRECTORIES:
+ CreateDirectories();
+ SetStage(StageT::PARSE_SOURCES);
+ break;
+ case StageT::PARSE_SOURCES:
+ if (ThreadsStartJobs(JobQueues_.Sources)) {
+ SetStage(StageT::PARSE_HEADERS);
+ }
+ break;
+ case StageT::PARSE_HEADERS:
+ if (ThreadsStartJobs(JobQueues_.Headers)) {
+ SetStage(StageT::MOC_PREDEFS);
+ }
+ break;
+ case StageT::MOC_PREDEFS:
+ if (ThreadsStartJobs(JobQueues_.MocPredefs)) {
+ SetStage(StageT::MOC_PROCESS);
+ }
+ break;
+ case StageT::MOC_PROCESS:
+ if (ThreadsStartJobs(JobQueues_.Moc)) {
+ SetStage(StageT::MOCS_COMPILATION);
+ }
+ break;
+ case StageT::MOCS_COMPILATION:
+ if (ThreadsJobsDone()) {
+ MocGenerateCompilation();
+ SetStage(StageT::UIC_PROCESS);
+ }
+ break;
+ case StageT::UIC_PROCESS:
+ if (ThreadsStartJobs(JobQueues_.Uic)) {
+ SetStage(StageT::SETTINGS_WRITE);
+ }
+ break;
+ case StageT::SETTINGS_WRITE:
+ SettingsFileWrite();
+ SetStage(StageT::FINISH);
+ break;
+ case StageT::FINISH:
+ if (ThreadsJobsDone()) {
+ // Clear all libuv handles
+ ThreadsStop();
+ UVRequest().reset();
+ // Set highest END stage manually
+ Stage_ = StageT::END;
+ }
+ break;
+ case StageT::END:
+ break;
+ }
+}
+
+void cmQtAutoGeneratorMocUic::SetStage(StageT stage)
+{
+ if (JobError_) {
+ stage = StageT::FINISH;
+ }
+ // Only allow to increase the stage
+ if (Stage_ < stage) {
+ Stage_ = stage;
+ UVRequest().send();
+ }
+}
+
+void cmQtAutoGeneratorMocUic::SettingsFileRead()
{
// Compose current settings strings
{
cmCryptoHash crypt(cmCryptoHash::AlgoSHA256);
std::string const sep(" ~~~ ");
- if (this->MocEnabled()) {
+ if (Moc_.Enabled) {
std::string str;
- str += this->MocExecutable;
+ str += Moc().Executable;
str += sep;
- str += cmJoin(this->MocAllOptions, ";");
+ str += cmJoin(Moc().AllOptions, ";");
str += sep;
- str += this->IncludeProjectDirsBefore ? "TRUE" : "FALSE";
+ str += Base().IncludeProjectDirsBefore ? "TRUE" : "FALSE";
str += sep;
- str += cmJoin(this->MocPredefsCmd, ";");
+ str += cmJoin(Moc().PredefsCmd, ";");
str += sep;
- this->SettingsStringMoc = crypt.HashString(str);
+ SettingsStringMoc_ = crypt.HashString(str);
}
- if (this->UicEnabled()) {
+ if (Uic().Enabled) {
std::string str;
- str += this->UicExecutable;
+ str += Uic().Executable;
str += sep;
- str += cmJoin(this->UicTargetOptions, ";");
- for (const auto& item : this->UicOptions) {
+ str += cmJoin(Uic().TargetOptions, ";");
+ for (const auto& item : Uic().Options) {
str += sep;
str += item.first;
str += sep;
str += cmJoin(item.second, ";");
}
str += sep;
- this->SettingsStringUic = crypt.HashString(str);
+ SettingsStringUic_ = crypt.HashString(str);
}
}
- // Read old settings
- if (makefile->ReadListFile(this->SettingsFile.c_str())) {
- {
- auto SMatch = [makefile](const char* key, std::string const& value) {
- return (value == makefile->GetSafeDefinition(key));
- };
- if (!SMatch(SettingsKeyMoc, this->SettingsStringMoc)) {
- this->MocSettingsChanged = true;
+ // Read old settings and compare
+ {
+ std::string content;
+ if (FileSys().FileRead(content, SettingsFile_)) {
+ if (Moc().Enabled) {
+ if (SettingsStringMoc_ != SettingsFind(content, "moc")) {
+ Moc_.SettingsChanged = true;
+ }
}
- if (!SMatch(SettingsKeyUic, this->SettingsStringUic)) {
- this->UicSettingsChanged = true;
+ if (Uic().Enabled) {
+ if (SettingsStringUic_ != SettingsFind(content, "uic")) {
+ Uic_.SettingsChanged = true;
+ }
+ }
+ // In case any setting changed remove the old settings file.
+ // This triggers a full rebuild on the next run if the current
+ // build is aborted before writing the current settings in the end.
+ if (Moc().SettingsChanged || Uic().SettingsChanged) {
+ FileSys().FileRemove(SettingsFile_);
+ }
+ } else {
+ // Settings file read failed
+ if (Moc().Enabled) {
+ Moc_.SettingsChanged = true;
+ }
+ if (Uic().Enabled) {
+ Uic_.SettingsChanged = true;
}
}
- // In case any setting changed remove the old settings file.
- // This triggers a full rebuild on the next run if the current
- // build is aborted before writing the current settings in the end.
- if (this->SettingsChanged()) {
- cmSystemTools::RemoveFile(this->SettingsFile);
- }
- } else {
- // If the file could not be read re-generate everythiung.
- this->MocSettingsChanged = true;
- this->UicSettingsChanged = true;
}
}
-bool cmQtAutoGeneratorMocUic::SettingsFileWrite()
+void cmQtAutoGeneratorMocUic::SettingsFileWrite()
{
- bool success = true;
+ std::lock_guard<std::mutex> jobsLock(JobsMutex_);
// Only write if any setting changed
- if (this->SettingsChanged()) {
- if (this->GetVerbose()) {
- this->LogInfo(cmQtAutoGen::GEN, "Writing settings file " +
- cmQtAutoGen::Quoted(this->SettingsFile));
+ if (!JobError_ && (Moc().SettingsChanged || Uic().SettingsChanged)) {
+ if (Log().Verbose()) {
+ Log().Info(GeneratorT::GEN,
+ "Writing settings file " + Quoted(SettingsFile_));
}
// Compose settings file content
- std::string settings;
+ std::string content;
{
- auto SettingAppend = [&settings](const char* key,
- std::string const& value) {
- settings += "set(";
- settings += key;
- settings += " ";
- settings += cmOutputConverter::EscapeForCMake(value);
- settings += ")\n";
+ auto SettingAppend = [&content](const char* key,
+ std::string const& value) {
+ if (!value.empty()) {
+ content += key;
+ content += ':';
+ content += value;
+ content += '\n';
+ }
};
- SettingAppend(SettingsKeyMoc, this->SettingsStringMoc);
- SettingAppend(SettingsKeyUic, this->SettingsStringUic);
+ SettingAppend("moc", SettingsStringMoc_);
+ SettingAppend("uic", SettingsStringUic_);
}
// Write settings file
- if (!this->FileWrite(cmQtAutoGen::GEN, this->SettingsFile, settings)) {
- this->LogFileError(cmQtAutoGen::GEN, this->SettingsFile,
- "Settings file writing failed");
+ if (!FileSys().FileWrite(GeneratorT::GEN, SettingsFile_, content)) {
+ Log().ErrorFile(GeneratorT::GEN, SettingsFile_,
+ "Settings file writing failed");
// Remove old settings file to trigger a full rebuild on the next run
- cmSystemTools::RemoveFile(this->SettingsFile);
- success = false;
+ FileSys().FileRemove(SettingsFile_);
+ RegisterJobError();
}
}
- return success;
}
-bool cmQtAutoGeneratorMocUic::Process(cmMakefile* makefile)
+void cmQtAutoGeneratorMocUic::CreateDirectories()
{
- // 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 mocs_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 mocs_compilation.cpp file.
-
- if (!this->InitInfoFile(makefile)) {
- return false;
- }
- // Read latest settings
- this->SettingsFileRead(makefile);
-
// Create AUTOGEN include directory
- {
- std::string const incDirAbs = cmSystemTools::CollapseCombinedPath(
- this->AutogenBuildDir, this->AutogenIncludeDir);
- if (!cmSystemTools::MakeDirectory(incDirAbs)) {
- this->LogFileError(cmQtAutoGen::GEN, incDirAbs,
- "Could not create directory");
- return false;
- }
- }
-
- // Parse source files
- for (const auto& item : this->SourceJobs) {
- if (!this->ParseSourceFile(item.first, item.second)) {
- return false;
- }
- }
- // Parse header files
- for (const auto& item : this->HeaderJobs) {
- if (!this->ParseHeaderFile(item.first, item.second)) {
- return false;
- }
- }
- // Read missing dependency information
- if (!this->ParsePostprocess()) {
- return false;
+ if (!FileSys().MakeDirectory(GeneratorT::GEN, Base().AutogenIncludeDirAbs)) {
+ RegisterJobError();
}
-
- // Generate files
- if (!this->MocGenerateAll()) {
- return false;
- }
- if (!this->UicGenerateAll()) {
- return false;
- }
-
- if (!this->SettingsFileWrite()) {
- return false;
- }
-
- return true;
}
-/**
- * @return True on success
- */
-bool cmQtAutoGeneratorMocUic::ParseSourceFile(std::string const& absFilename,
- const SourceJob& job)
+bool cmQtAutoGeneratorMocUic::ThreadsStartJobs(JobQueueT& queue)
{
- std::string contentText;
- std::string error;
- bool success = this->FileRead(contentText, absFilename, &error);
- if (success) {
- if (!contentText.empty()) {
- if (job.Moc) {
- success = this->MocParseSourceContent(absFilename, contentText);
- }
- if (success && job.Uic) {
- success = this->UicParseContent(absFilename, contentText);
+ bool done = false;
+ std::size_t queueSize = queue.size();
+
+ // Change the active queue
+ {
+ std::lock_guard<std::mutex> jobsLock(JobsMutex_);
+ // Check if there are still unfinished jobs from the previous queue
+ if (JobsRemain_ == 0) {
+ if (!JobThreadsAbort_) {
+ JobQueue_.swap(queue);
+ JobsRemain_ = queueSize;
+ } else {
+ // Abort requested
+ queue.clear();
+ queueSize = 0;
}
- } else {
- this->LogFileWarning(cmQtAutoGen::GEN, absFilename,
- "The source file is empty");
+ done = true;
}
- } else {
- this->LogFileError(cmQtAutoGen::GEN, absFilename,
- "Could not read the source file: " + error);
}
- return success;
-}
-/**
- * @return True on success
- */
-bool cmQtAutoGeneratorMocUic::ParseHeaderFile(std::string const& absFilename,
- const SourceJob& job)
-{
- std::string contentText;
- std::string error;
- bool success = this->FileRead(contentText, absFilename, &error);
- if (success) {
- if (!contentText.empty()) {
- if (job.Moc) {
- this->MocParseHeaderContent(absFilename, contentText);
- }
- if (job.Uic) {
- success = this->UicParseContent(absFilename, contentText);
+ if (done && (queueSize != 0)) {
+ // Start new threads on demand
+ if (Workers_.empty()) {
+ Workers_.resize(Base().NumThreads);
+ for (auto& item : Workers_) {
+ item = cm::make_unique<WorkerT>(this, UVLoop());
}
} else {
- this->LogFileWarning(cmQtAutoGen::GEN, absFilename,
- "The header file is empty");
- }
- } else {
- this->LogFileError(cmQtAutoGen::GEN, absFilename,
- "Could not read the header file: " + error);
- }
- return success;
-}
-
-/**
- * @return True on success
- */
-bool cmQtAutoGeneratorMocUic::ParsePostprocess()
-{
- bool success = true;
- // Read missing dependencies
- for (auto& item : this->MocJobsIncluded) {
- if (!item->DependsValid) {
- std::string content;
- std::string error;
- if (this->FileRead(content, item->SourceFile, &error)) {
- this->MocFindDepends(item->SourceFile, content, item->Depends);
- item->DependsValid = true;
+ // Notify threads
+ if (queueSize == 1) {
+ JobsConditionRead_.notify_one();
} else {
- std::string emsg = "Could not read file\n ";
- emsg += item->SourceFile;
- emsg += "\nrequired by moc include \"";
- emsg += item->IncludeString;
- emsg += "\".\n";
- emsg += error;
- this->LogFileError(cmQtAutoGen::MOC, item->Includer, emsg);
- success = false;
- break;
+ JobsConditionRead_.notify_all();
}
}
}
- return success;
-}
-
-/**
- * @brief Tests if the file should be ignored for moc scanning
- * @return True if the file should be ignored
- */
-bool cmQtAutoGeneratorMocUic::MocSkip(std::string const& absFilename) const
-{
- if (this->MocEnabled()) {
- // Test if the file name is on the skip list
- if (!ListContains(this->MocSkipList, absFilename)) {
- return false;
- }
- }
- return true;
-}
-/**
- * @brief Tests if the C++ content requires moc processing
- * @return True if moc is required
- */
-bool cmQtAutoGeneratorMocUic::MocRequired(std::string const& contentText,
- std::string* macroName)
-{
- for (KeyRegExp& filter : this->MocMacroFilters) {
- // Run a simple find string operation before the expensive
- // regular expression check
- if (contentText.find(filter.Key) != std::string::npos) {
- if (filter.RegExp.find(contentText)) {
- // Return macro name on demand
- if (macroName != nullptr) {
- *macroName = filter.Key;
- }
- return true;
- }
- }
- }
- return false;
+ return done;
}
-std::string cmQtAutoGeneratorMocUic::MocStringMacros() const
+void cmQtAutoGeneratorMocUic::ThreadsStop()
{
- std::string res;
- const auto itB = this->MocMacroFilters.cbegin();
- const auto itE = this->MocMacroFilters.cend();
- const auto itL = itE - 1;
- auto itC = itB;
- for (; itC != itE; ++itC) {
- // Separator
- if (itC != itB) {
- if (itC != itL) {
- res += ", ";
- } else {
- res += " or ";
- }
- }
- // Key
- res += itC->Key;
+ if (!Workers_.empty()) {
+ // Clear all jobs
+ {
+ std::lock_guard<std::mutex> jobsLock(JobsMutex_);
+ JobThreadsAbort_ = true;
+ JobsRemain_ -= JobQueue_.size();
+ JobQueue_.clear();
+
+ JobQueues_.Sources.clear();
+ JobQueues_.Headers.clear();
+ JobQueues_.MocPredefs.clear();
+ JobQueues_.Moc.clear();
+ JobQueues_.Uic.clear();
+ }
+ // Wake threads
+ JobsConditionRead_.notify_all();
+ // Join and clear threads
+ Workers_.clear();
}
- return res;
}
-std::string cmQtAutoGeneratorMocUic::MocStringHeaders(
- std::string const& fileBase) const
+bool cmQtAutoGeneratorMocUic::ThreadsJobsDone()
{
- std::string res = fileBase;
- res += ".{";
- res += cmJoin(this->HeaderExtensions, ",");
- res += "}";
- return res;
+ std::lock_guard<std::mutex> jobsLock(JobsMutex_);
+ return (JobsRemain_ == 0);
}
-std::string cmQtAutoGeneratorMocUic::MocFindIncludedHeader(
- std::string const& sourcePath, std::string const& includeBase) const
+void cmQtAutoGeneratorMocUic::WorkerSwapJob(JobHandleT& jobHandle)
{
- std::string header;
- // Search in vicinity of the source
- if (!this->FindHeader(header, sourcePath + includeBase)) {
- // Search in include directories
- for (std::string const& path : this->MocIncludePaths) {
- std::string fullPath = path;
- fullPath.push_back('/');
- fullPath += includeBase;
- if (this->FindHeader(header, fullPath)) {
- break;
- }
- }
- }
- // Sanitize
- if (!header.empty()) {
- header = cmSystemTools::GetRealPath(header);
+ bool const jobProcessed(jobHandle);
+ if (jobProcessed) {
+ jobHandle.reset(nullptr);
}
- return header;
-}
-
-bool cmQtAutoGeneratorMocUic::MocFindIncludedFile(
- std::string& absFile, std::string const& sourcePath,
- std::string const& includeString) const
-{
- bool success = false;
- // Search in vicinity of the source
{
- std::string testPath = sourcePath;
- testPath += includeString;
- if (cmSystemTools::FileExists(testPath.c_str())) {
- absFile = cmSystemTools::GetRealPath(testPath);
- success = true;
- }
- }
- // Search in include directories
- if (!success) {
- for (std::string const& path : this->MocIncludePaths) {
- std::string fullPath = path;
- fullPath.push_back('/');
- fullPath += includeString;
- if (cmSystemTools::FileExists(fullPath.c_str())) {
- absFile = cmSystemTools::GetRealPath(fullPath);
- success = true;
- break;
+ std::unique_lock<std::mutex> jobsLock(JobsMutex_);
+ // Reduce the remaining job count and notify the libuv loop
+ // when all jobs are done
+ if (jobProcessed) {
+ --JobsRemain_;
+ if (JobsRemain_ == 0) {
+ UVRequest().send();
}
}
- }
- return success;
-}
-
-bool cmQtAutoGeneratorMocUic::MocDependFilterPush(std::string const& key,
- std::string const& regExp)
-{
- std::string error;
- if (!key.empty()) {
- if (!regExp.empty()) {
- KeyRegExp filter;
- filter.Key = key;
- if (filter.RegExp.compile(regExp)) {
- this->MocDependFilters.push_back(std::move(filter));
- } else {
- error = "Regular expression compiling failed";
- }
- } else {
- error = "Regular expression is empty";
- }
- } else {
- error = "Key is empty";
- }
- if (!error.empty()) {
- std::string emsg = "AUTOMOC_DEPEND_FILTERS: ";
- emsg += error;
- emsg += "\n";
- emsg += " Key: ";
- emsg += cmQtAutoGen::Quoted(key);
- emsg += "\n";
- emsg += " RegExp: ";
- emsg += cmQtAutoGen::Quoted(regExp);
- emsg += "\n";
- this->LogError(cmQtAutoGen::MOC, emsg);
- return false;
- }
- return true;
-}
-
-void cmQtAutoGeneratorMocUic::MocFindDepends(std::string const& absFilename,
- std::string const& contentText,
- std::set<std::string>& depends)
-{
- if (this->MocDependFilters.empty() && contentText.empty()) {
- return;
- }
-
- std::vector<std::string> matches;
- for (KeyRegExp& filter : this->MocDependFilters) {
- // Run a simple find string check
- if (contentText.find(filter.Key) != std::string::npos) {
- // Run the expensive regular expression check loop
- const char* contentChars = contentText.c_str();
- while (filter.RegExp.find(contentChars)) {
- std::string match = filter.RegExp.match(1);
- if (!match.empty()) {
- matches.emplace_back(std::move(match));
- }
- contentChars += filter.RegExp.end();
- }
+ // Wait for new jobs
+ while (!JobThreadsAbort_ && JobQueue_.empty()) {
+ JobsConditionRead_.wait(jobsLock);
}
- }
-
- if (!matches.empty()) {
- std::string const sourcePath = SubDirPrefix(absFilename);
- for (std::string const& match : matches) {
- // Find the dependency file
- std::string incFile;
- if (this->MocFindIncludedFile(incFile, sourcePath, match)) {
- depends.insert(incFile);
- if (this->GetVerbose()) {
- this->LogInfo(cmQtAutoGen::MOC, "Found dependency:\n " +
- cmQtAutoGen::Quoted(absFilename) + "\n " +
- cmQtAutoGen::Quoted(incFile));
- }
- } else {
- this->LogFileWarning(cmQtAutoGen::MOC, absFilename,
- "Could not find dependency file " +
- cmQtAutoGen::Quoted(match));
- }
+ // Try to pick up a new job handle
+ if (!JobThreadsAbort_ && !JobQueue_.empty()) {
+ jobHandle = std::move(JobQueue_.front());
+ JobQueue_.pop_front();
}
}
}
-/**
- * @return True on success
- */
-bool cmQtAutoGeneratorMocUic::MocParseSourceContent(
- std::string const& absFilename, std::string const& contentText)
+void cmQtAutoGeneratorMocUic::ParallelRegisterJobError()
{
- if (this->GetVerbose()) {
- this->LogInfo(cmQtAutoGen::MOC, "Checking: " + absFilename);
- }
-
- auto AddJob = [this, &absFilename](std::string const& sourceFile,
- std::string const& includeString,
- std::string const* content) {
- auto job = cm::make_unique<MocJobIncluded>();
- job->SourceFile = sourceFile;
- job->BuildFileRel = this->AutogenIncludeDir;
- job->BuildFileRel += includeString;
- job->Includer = absFilename;
- job->IncludeString = includeString;
- job->DependsValid = (content != nullptr);
- if (job->DependsValid) {
- this->MocFindDepends(sourceFile, *content, job->Depends);
- }
- this->MocJobsIncluded.push_back(std::move(job));
- };
-
- struct MocInc
- {
- std::string Inc; // full include string
- std::string Dir; // include string directory
- std::string Base; // include string file base
- };
-
- // Extract moc includes from file
- std::vector<MocInc> mocIncsUsc;
- std::vector<MocInc> mocIncsDot;
- {
- const char* contentChars = contentText.c_str();
- if (strstr(contentChars, "moc") != nullptr) {
- while (this->MocRegExpInclude.find(contentChars)) {
- std::string incString = this->MocRegExpInclude.match(1);
- std::string incDir(SubDirPrefix(incString));
- std::string incBase =
- cmSystemTools::GetFilenameWithoutLastExtension(incString);
- if (cmHasLiteralPrefix(incBase, "moc_")) {
- // moc_<BASE>.cxx
- // Remove the moc_ part from the base name
- mocIncsUsc.push_back(MocInc{ std::move(incString), std::move(incDir),
- incBase.substr(4) });
- } else {
- // <BASE>.moc
- mocIncsDot.push_back(MocInc{ std::move(incString), std::move(incDir),
- std::move(incBase) });
- }
- // Forward content pointer
- contentChars += this->MocRegExpInclude.end();
- }
- }
- }
-
- std::string selfMacroName;
- const bool selfRequiresMoc = this->MocRequired(contentText, &selfMacroName);
-
- // Check if there is anything to do
- if (!selfRequiresMoc && mocIncsUsc.empty() && mocIncsDot.empty()) {
- return true;
- }
-
- // Scan file variables
- std::string const scanFileDir = SubDirPrefix(absFilename);
- std::string const scanFileBase =
- cmSystemTools::GetFilenameWithoutLastExtension(absFilename);
- // Relaxed mode variables
- bool ownDotMocIncluded = false;
- std::string ownMocUscInclude;
- std::string ownMocUscHeader;
-
- // Process moc_<BASE>.cxx includes
- for (const MocInc& mocInc : mocIncsUsc) {
- std::string const header =
- this->MocFindIncludedHeader(scanFileDir, mocInc.Dir + mocInc.Base);
- if (!header.empty()) {
- // Check if header is skipped
- if (this->MocSkip(header)) {
- continue;
- }
- // Register moc job
- AddJob(header, mocInc.Inc, nullptr);
- // Store meta information for relaxed mode
- if (this->MocRelaxedMode && (mocInc.Base == scanFileBase)) {
- ownMocUscInclude = mocInc.Inc;
- ownMocUscHeader = header;
- }
- } else {
- std::string emsg = "The file includes the moc file ";
- emsg += cmQtAutoGen::Quoted(mocInc.Inc);
- emsg += ", but could not find the header ";
- emsg += cmQtAutoGen::Quoted(this->MocStringHeaders(mocInc.Base));
- this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg);
- return false;
- }
- }
-
- // Process <BASE>.moc includes
- for (const MocInc& mocInc : mocIncsDot) {
- const bool ownMoc = (mocInc.Base == scanFileBase);
- if (this->MocRelaxedMode) {
- // Relaxed mode
- if (selfRequiresMoc && ownMoc) {
- // Add self
- AddJob(absFilename, mocInc.Inc, &contentText);
- ownDotMocIncluded = true;
- } else {
- // In relaxed mode try to find a header instead but issue a warning.
- // This is for KDE4 compatibility
- std::string const header =
- this->MocFindIncludedHeader(scanFileDir, mocInc.Dir + mocInc.Base);
- if (!header.empty()) {
- // Check if header is skipped
- if (this->MocSkip(header)) {
- continue;
- }
- // Register moc job
- AddJob(header, mocInc.Inc, nullptr);
- if (!selfRequiresMoc) {
- if (ownMoc) {
- std::string emsg = "The file includes the moc file ";
- emsg += cmQtAutoGen::Quoted(mocInc.Inc);
- emsg += ", but does not contain a ";
- emsg += this->MocStringMacros();
- emsg += " macro.\nRunning moc on\n ";
- emsg += cmQtAutoGen::Quoted(header);
- emsg += "!\nBetter include ";
- emsg += cmQtAutoGen::Quoted("moc_" + mocInc.Base + ".cpp");
- emsg += " for a compatibility with strict mode.\n"
- "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n";
- this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg);
- } else {
- std::string emsg = "The file includes the moc file ";
- emsg += cmQtAutoGen::Quoted(mocInc.Inc);
- emsg += " instead of ";
- emsg += cmQtAutoGen::Quoted("moc_" + mocInc.Base + ".cpp");
- emsg += ".\nRunning moc on\n ";
- emsg += cmQtAutoGen::Quoted(header);
- emsg += "!\nBetter include ";
- emsg += cmQtAutoGen::Quoted("moc_" + mocInc.Base + ".cpp");
- emsg += " for compatibility with strict mode.\n"
- "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n";
- this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg);
- }
- }
- } else {
- std::string emsg = "The file includes the moc file ";
- emsg += cmQtAutoGen::Quoted(mocInc.Inc);
- emsg += ", which seems to be the moc file from a different "
- "source file. CMake also could not find a matching "
- "header.";
- this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg);
- return false;
- }
- }
- } else {
- // Strict mode
- if (ownMoc) {
- // Include self
- AddJob(absFilename, mocInc.Inc, &contentText);
- ownDotMocIncluded = true;
- // Accept but issue a warning if moc isn't required
- if (!selfRequiresMoc) {
- std::string emsg = "The file includes the moc file ";
- emsg += cmQtAutoGen::Quoted(mocInc.Inc);
- emsg += ", but does not contain a ";
- emsg += this->MocStringMacros();
- emsg += " macro.";
- this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg);
- }
- } else {
- // Don't allow <BASE>.moc include other than self in strict mode
- std::string emsg = "The file includes the moc file ";
- emsg += cmQtAutoGen::Quoted(mocInc.Inc);
- emsg += ", which seems to be the moc file from a different "
- "source file.\nThis is not supported. Include ";
- emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc");
- emsg += " to run moc on this source file.";
- this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg);
- return false;
- }
- }
- }
-
- if (selfRequiresMoc && !ownDotMocIncluded) {
- // In this case, check whether the scanned file itself contains a Q_OBJECT.
- // If this is the case, the moc_foo.cpp should probably be generated from
- // foo.cpp instead of foo.h, because otherwise it won't build.
- // But warn, since this is not how it is supposed to be used.
- if (this->MocRelaxedMode && !ownMocUscInclude.empty()) {
- // This is for KDE4 compatibility:
- std::string emsg = "The file contains a ";
- emsg += selfMacroName;
- emsg += " macro, but does not include ";
- emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc");
- emsg += ". Instead it includes ";
- emsg += cmQtAutoGen::Quoted(ownMocUscInclude);
- emsg += ".\nRunning moc on\n ";
- emsg += cmQtAutoGen::Quoted(absFilename);
- emsg += "!\nBetter include ";
- emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc");
- emsg += " for compatibility with strict mode.\n"
- "(CMAKE_AUTOMOC_RELAXED_MODE warning)";
- this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg);
-
- // Remove own header job
- {
- auto itC = this->MocJobsIncluded.begin();
- auto itE = this->MocJobsIncluded.end();
- for (; itC != itE; ++itC) {
- if ((*itC)->SourceFile == ownMocUscHeader) {
- if ((*itC)->IncludeString == ownMocUscInclude) {
- this->MocJobsIncluded.erase(itC);
- break;
- }
- }
- }
- }
- // Add own source job
- AddJob(absFilename, ownMocUscInclude, &contentText);
- } else {
- // Otherwise always error out since it will not compile:
- std::string emsg = "The file contains a ";
- emsg += selfMacroName;
- emsg += " macro, but does not include ";
- emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc");
- emsg += "!\nConsider to\n - add #include \"";
- emsg += scanFileBase;
- emsg += ".moc\"\n - enable SKIP_AUTOMOC for this file";
- this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg);
- return false;
- }
- }
- return true;
+ std::lock_guard<std::mutex> jobsLock(JobsMutex_);
+ RegisterJobError();
}
-void cmQtAutoGeneratorMocUic::MocParseHeaderContent(
- std::string const& absFilename, std::string const& contentText)
+// Private method that requires cmQtAutoGeneratorMocUic::JobsMutex_ to be
+// locked
+void cmQtAutoGeneratorMocUic::RegisterJobError()
{
- if (this->GetVerbose()) {
- this->LogInfo(cmQtAutoGen::MOC, "Checking: " + absFilename);
- }
-
- auto const fit =
- std::find_if(this->MocJobsIncluded.cbegin(), this->MocJobsIncluded.cend(),
- [&absFilename](std::unique_ptr<MocJobIncluded> const& job) {
- return job->SourceFile == absFilename;
- });
- if (fit == this->MocJobsIncluded.cend()) {
- if (this->MocRequired(contentText)) {
- auto job = cm::make_unique<MocJobAuto>();
- job->SourceFile = absFilename;
- {
- std::string& bld = job->BuildFileRel;
- bld = this->FilePathChecksum.getPart(absFilename);
- bld += '/';
- bld += "moc_";
- bld += cmSystemTools::GetFilenameWithoutLastExtension(absFilename);
- if (this->MultiConfig != cmQtAutoGen::SINGLE) {
- bld += this->ConfigSuffix;
- }
- bld += ".cpp";
- }
- this->MocFindDepends(absFilename, contentText, job->Depends);
- this->MocJobsAuto.push_back(std::move(job));
+ JobError_ = true;
+ if (!JobThreadsAbort_) {
+ JobThreadsAbort_ = true;
+ // Clear remaining jobs
+ if (JobsRemain_ != 0) {
+ JobsRemain_ -= JobQueue_.size();
+ JobQueue_.clear();
}
}
}
-bool cmQtAutoGeneratorMocUic::MocGenerateAll()
+bool cmQtAutoGeneratorMocUic::ParallelJobPushMoc(JobHandleT& jobHandle)
{
- if (!this->MocEnabled()) {
- return true;
- }
-
- // Look for name collisions in included moc files
- {
- bool collision = false;
- std::map<std::string, std::vector<MocJobIncluded const*>> collisions;
- for (auto const& job : this->MocJobsIncluded) {
- auto& list = collisions[job->IncludeString];
- if (!list.empty()) {
- collision = true;
- }
- list.push_back(job.get());
- }
- if (collision) {
- std::string emsg =
- "Included moc files with the same name will be "
- "generated from different sources.\n"
- "Consider to\n"
- " - not include the \"moc_<NAME>.cpp\" file\n"
- " - add a directory prefix to a \"<NAME>.moc\" include "
- "(e.g \"sub/<NAME>.moc\")\n"
- " - rename the source file(s)\n"
- "Include conflicts\n"
- "-----------------\n";
- const auto& colls = collisions;
- for (auto const& coll : colls) {
- if (coll.second.size() > 1) {
- emsg += cmQtAutoGen::Quoted(coll.first);
- emsg += " included in\n";
- for (const MocJobIncluded* job : coll.second) {
- emsg += " - ";
- emsg += cmQtAutoGen::Quoted(job->Includer);
- emsg += "\n";
- }
- emsg += "would be generated from\n";
- for (const MocJobIncluded* job : coll.second) {
- emsg += " - ";
- emsg += cmQtAutoGen::Quoted(job->SourceFile);
- emsg += "\n";
+ std::lock_guard<std::mutex> jobsLock(JobsMutex_);
+ if (!JobThreadsAbort_) {
+ bool pushJobHandle = true;
+ // Do additional tests if this is an included moc job
+ const JobMocT& mocJob(static_cast<JobMocT&>(*jobHandle));
+ if (!mocJob.IncludeString.empty()) {
+ // Register included moc file and look for collisions
+ MocIncludedFiles_.emplace(mocJob.SourceFile);
+ if (!MocIncludedStrings_.emplace(mocJob.IncludeString).second) {
+ // Another source file includes the same moc file!
+ for (const JobHandleT& otherHandle : JobQueues_.Moc) {
+ const JobMocT& otherJob(static_cast<JobMocT&>(*otherHandle));
+ if (otherJob.IncludeString == mocJob.IncludeString) {
+ // Check if the same moc file would be generated from different
+ // source files which is an error.
+ if (otherJob.SourceFile != mocJob.SourceFile) {
+ // Include string collision
+ std::string error = "The two source files\n ";
+ error += Quoted(mocJob.IncluderFile);
+ error += " and\n ";
+ error += Quoted(otherJob.IncluderFile);
+ error += "\ncontain the the same moc include string ";
+ error += Quoted(mocJob.IncludeString);
+ error += "\nbut the moc file would be generated from different "
+ "source files\n ";
+ error += Quoted(mocJob.SourceFile);
+ error += " and\n ";
+ error += Quoted(otherJob.SourceFile);
+ error += ".\nConsider to\n"
+ "- not include the \"moc_<NAME>.cpp\" file\n"
+ "- add a directory prefix to a \"<NAME>.moc\" include "
+ "(e.g \"sub/<NAME>.moc\")\n"
+ "- rename the source file(s)\n";
+ Log().Error(GeneratorT::MOC, error);
+ RegisterJobError();
+ }
+ // Do not push this job in since the included moc file already
+ // gets generated by an other job.
+ pushJobHandle = false;
+ break;
}
}
}
- this->LogError(cmQtAutoGen::MOC, emsg);
- return false;
}
- }
-
- // (Re)generate moc_predefs.h on demand
- if (!this->MocPredefsCmd.empty()) {
- if (this->MocSettingsChanged ||
- !cmSystemTools::FileExists(this->MocPredefsFileAbs)) {
- if (this->GetVerbose()) {
- this->LogBold("Generating MOC predefs " + this->MocPredefsFileRel);
- }
-
- std::string output;
- {
- // Compose command
- std::vector<std::string> cmd = this->MocPredefsCmd;
- // Add includes
- cmd.insert(cmd.end(), this->MocIncludes.begin(),
- this->MocIncludes.end());
- // Add definitions
- for (std::string const& def : this->MocDefinitions) {
- cmd.push_back("-D" + def);
- }
- // Execute command
- if (!this->RunCommand(cmd, output)) {
- this->LogCommandError(cmQtAutoGen::MOC,
- "moc_predefs generation failed", cmd, output);
- return false;
- }
- }
-
- // (Re)write predefs file only on demand
- if (this->FileDiffers(this->MocPredefsFileAbs, output)) {
- if (this->FileWrite(cmQtAutoGen::MOC, this->MocPredefsFileAbs,
- output)) {
- this->MocPredefsChanged = true;
- } else {
- this->LogFileError(cmQtAutoGen::MOC, this->MocPredefsFileAbs,
- "moc_predefs file writing failed");
- return false;
- }
- } else {
- // Touch to update the time stamp
- if (this->GetVerbose()) {
- this->LogInfo(cmQtAutoGen::MOC,
- "Touching moc_predefs " + this->MocPredefsFileRel);
- }
- cmSystemTools::Touch(this->MocPredefsFileAbs, false);
- }
- }
-
- // Add moc_predefs.h to moc file dependencies
- for (auto const& item : this->MocJobsIncluded) {
- item->Depends.insert(this->MocPredefsFileAbs);
- }
- for (auto const& item : this->MocJobsAuto) {
- item->Depends.insert(this->MocPredefsFileAbs);
- }
- }
-
- // Generate moc files that are included by source files.
- for (auto const& item : this->MocJobsIncluded) {
- if (!this->MocGenerateFile(*item)) {
- return false;
- }
- }
- // Generate moc files that are _not_ included by source files.
- bool autoNameGenerated = false;
- for (auto const& item : this->MocJobsAuto) {
- if (!this->MocGenerateFile(*item, &autoNameGenerated)) {
- return false;
- }
- }
-
- // Compose mocs compilation file content
- {
- std::string mocs =
- "// This file is autogenerated. Changes will be overwritten.\n";
- if (this->MocJobsAuto.empty()) {
- // Placeholder content
- mocs +=
- "// No files found that require moc or the moc files are included\n";
- mocs += "enum some_compilers { need_more_than_nothing };\n";
- } else {
- // Valid content
- for (const auto& item : this->MocJobsAuto) {
- mocs += "#include \"";
- mocs += item->BuildFileRel;
- mocs += "\"\n";
- }
- }
-
- if (this->FileDiffers(this->MocCompFileAbs, mocs)) {
- // Actually write mocs compilation file
- if (this->GetVerbose()) {
- this->LogBold("Generating MOC compilation " + this->MocCompFileRel);
- }
- if (!this->FileWrite(cmQtAutoGen::MOC, this->MocCompFileAbs, mocs)) {
- this->LogFileError(cmQtAutoGen::MOC, this->MocCompFileAbs,
- "mocs compilation file writing failed");
- return false;
- }
- } else if (autoNameGenerated) {
- // Only touch mocs compilation file
- if (this->GetVerbose()) {
- this->LogInfo(cmQtAutoGen::MOC,
- "Touching mocs compilation " + this->MocCompFileRel);
- }
- cmSystemTools::Touch(this->MocCompFileAbs, false);
+ // Push job on demand
+ if (pushJobHandle) {
+ JobQueues_.Moc.emplace_back(std::move(jobHandle));
}
}
-
- return true;
+ return !JobError_;
}
-/**
- * @return True on success
- */
-bool cmQtAutoGeneratorMocUic::MocGenerateFile(const MocJobAuto& mocJob,
- bool* generated)
+bool cmQtAutoGeneratorMocUic::ParallelJobPushUic(JobHandleT& jobHandle)
{
- bool success = true;
-
- std::string const mocFileAbs = cmSystemTools::CollapseCombinedPath(
- this->AutogenBuildDir, mocJob.BuildFileRel);
-
- bool generate = false;
- std::string generateReason;
- if (!generate && !cmSystemTools::FileExists(mocFileAbs.c_str())) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(mocFileAbs);
- generateReason += " from its source file ";
- generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile);
- generateReason += " because it doesn't exist";
- }
- generate = true;
- }
- if (!generate && this->MocSettingsChanged) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(mocFileAbs);
- generateReason += " from ";
- generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile);
- generateReason += " because the MOC settings changed";
- }
- generate = true;
- }
- if (!generate && this->MocPredefsChanged) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(mocFileAbs);
- generateReason += " from ";
- generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile);
- generateReason += " because moc_predefs.h changed";
- }
- generate = true;
- }
- if (!generate) {
- std::string error;
- if (FileIsOlderThan(mocFileAbs, mocJob.SourceFile, &error)) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(mocFileAbs);
- generateReason += " because it's older than its source file ";
- generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile);
- }
- generate = true;
- } else {
- if (!error.empty()) {
- this->LogError(cmQtAutoGen::MOC, error);
- success = false;
- }
- }
- }
- if (success && !generate) {
- // Test if a dependency file is newer
- std::string error;
- for (std::string const& depFile : mocJob.Depends) {
- if (FileIsOlderThan(mocFileAbs, depFile, &error)) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(mocFileAbs);
- generateReason += " from ";
- generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile);
- generateReason += " because it is older than ";
- generateReason += cmQtAutoGen::Quoted(depFile);
+ std::lock_guard<std::mutex> jobsLock(JobsMutex_);
+ if (!JobThreadsAbort_) {
+ bool pushJobHandle = true;
+ // Look for include collisions.
+ const JobUicT& uicJob(static_cast<JobUicT&>(*jobHandle));
+ for (const JobHandleT& otherHandle : JobQueues_.Uic) {
+ const JobUicT& otherJob(static_cast<JobUicT&>(*otherHandle));
+ if (otherJob.IncludeString == uicJob.IncludeString) {
+ // Check if the same uic file would be generated from different
+ // source files which would be an error.
+ if (otherJob.SourceFile != uicJob.SourceFile) {
+ // Include string collision
+ std::string error = "The two source files\n ";
+ error += Quoted(uicJob.IncluderFile);
+ error += " and\n ";
+ error += Quoted(otherJob.IncluderFile);
+ error += "\ncontain the the same uic include string ";
+ error += Quoted(uicJob.IncludeString);
+ error += "\nbut the uic file would be generated from different "
+ "source files\n ";
+ error += Quoted(uicJob.SourceFile);
+ error += " and\n ";
+ error += Quoted(otherJob.SourceFile);
+ error +=
+ ".\nConsider to\n"
+ "- add a directory prefix to a \"ui_<NAME>.h\" include "
+ "(e.g \"sub/ui_<NAME>.h\")\n"
+ "- rename the <NAME>.ui file(s) and adjust the \"ui_<NAME>.h\" "
+ "include(s)\n";
+ Log().Error(GeneratorT::UIC, error);
+ RegisterJobError();
}
- generate = true;
- break;
- }
- if (!error.empty()) {
- this->LogError(cmQtAutoGen::MOC, error);
- success = false;
+ // Do not push this job in since the uic file already
+ // gets generated by an other job.
+ pushJobHandle = false;
break;
}
}
- }
-
- if (generate) {
- // Log
- if (this->GetVerbose()) {
- this->LogBold("Generating MOC source " + mocJob.BuildFileRel);
- this->LogInfo(cmQtAutoGen::MOC, generateReason);
- }
-
- // Make sure the parent directory exists
- if (this->MakeParentDirectory(cmQtAutoGen::MOC, mocFileAbs)) {
- // Compose moc command
- std::vector<std::string> cmd;
- cmd.push_back(this->MocExecutable);
- // Add options
- cmd.insert(cmd.end(), this->MocAllOptions.begin(),
- this->MocAllOptions.end());
- // Add predefs include
- if (!this->MocPredefsFileAbs.empty()) {
- cmd.push_back("--include");
- cmd.push_back(this->MocPredefsFileAbs);
- }
- cmd.push_back("-o");
- cmd.push_back(mocFileAbs);
- cmd.push_back(mocJob.SourceFile);
-
- // Execute moc command
- std::string output;
- if (this->RunCommand(cmd, output)) {
- // Success
- if (generated != nullptr) {
- *generated = true;
- }
- } else {
- // Moc command failed
- {
- std::string emsg = "moc failed for\n ";
- emsg += cmQtAutoGen::Quoted(mocJob.SourceFile);
- this->LogCommandError(cmQtAutoGen::MOC, emsg, cmd, output);
- }
- cmSystemTools::RemoveFile(mocFileAbs);
- success = false;
- }
- } else {
- // Parent directory creation failed
- success = false;
+ if (pushJobHandle) {
+ JobQueues_.Uic.emplace_back(std::move(jobHandle));
}
}
- return success;
+ return !JobError_;
}
-/**
- * @brief Tests if the file name is in the skip list
- */
-bool cmQtAutoGeneratorMocUic::UicSkip(std::string const& absFilename) const
+bool cmQtAutoGeneratorMocUic::ParallelMocIncluded(
+ std::string const& sourceFile)
{
- if (this->UicEnabled()) {
- // Test if the file name is on the skip list
- if (!ListContains(this->UicSkipList, absFilename)) {
- return false;
- }
- }
- return true;
+ std::lock_guard<std::mutex> mocLock(JobsMutex_);
+ return (MocIncludedFiles_.find(sourceFile) != MocIncludedFiles_.end());
}
-bool cmQtAutoGeneratorMocUic::UicParseContent(std::string const& absFilename,
- std::string const& contentText)
+void cmQtAutoGeneratorMocUic::ParallelMocAutoRegister(
+ std::string const& mocFile)
{
- if (this->GetVerbose()) {
- this->LogInfo(cmQtAutoGen::UIC, "Checking: " + absFilename);
- }
-
- std::vector<std::string> includes;
- // Extracte includes
- {
- const char* contentChars = contentText.c_str();
- if (strstr(contentChars, "ui_") != nullptr) {
- while (this->UicRegExpInclude.find(contentChars)) {
- includes.push_back(this->UicRegExpInclude.match(1));
- contentChars += this->UicRegExpInclude.end();
- }
- }
- }
-
- for (std::string const& includeString : includes) {
- std::string uiInputFile;
- if (!UicFindIncludedFile(uiInputFile, absFilename, includeString)) {
- return false;
- }
- // Check if this file should be skipped
- if (this->UicSkip(uiInputFile)) {
- continue;
- }
- // Check if the job already exists
- bool jobExists = false;
- for (const auto& job : this->UicJobs) {
- if ((job->SourceFile == uiInputFile) &&
- (job->IncludeString == includeString)) {
- jobExists = true;
- break;
- }
- }
- if (!jobExists) {
- auto job = cm::make_unique<UicJob>();
- job->SourceFile = uiInputFile;
- job->BuildFileRel = this->AutogenIncludeDir;
- job->BuildFileRel += includeString;
- job->Includer = absFilename;
- job->IncludeString = includeString;
- this->UicJobs.push_back(std::move(job));
- }
- }
-
- return true;
+ std::lock_guard<std::mutex> mocLock(JobsMutex_);
+ MocAutoFiles_.emplace(mocFile);
}
-bool cmQtAutoGeneratorMocUic::UicFindIncludedFile(
- std::string& absFile, std::string const& sourceFile,
- std::string const& includeString)
+void cmQtAutoGeneratorMocUic::ParallelMocAutoUpdated()
{
- bool success = false;
- std::string searchFile =
- cmSystemTools::GetFilenameWithoutLastExtension(includeString).substr(3);
- searchFile += ".ui";
- // Collect search paths list
- std::vector<std::string> testFiles;
- {
- std::string const searchPath = SubDirPrefix(includeString);
-
- std::string searchFileFull;
- if (!searchPath.empty()) {
- searchFileFull = searchPath;
- searchFileFull += searchFile;
- }
- // Vicinity of the source
- {
- std::string const sourcePath = SubDirPrefix(sourceFile);
- testFiles.push_back(sourcePath + searchFile);
- if (!searchPath.empty()) {
- testFiles.push_back(sourcePath + searchFileFull);
- }
- }
- // AUTOUIC search paths
- if (!this->UicSearchPaths.empty()) {
- for (std::string const& sPath : this->UicSearchPaths) {
- testFiles.push_back((sPath + "/").append(searchFile));
- }
- if (!searchPath.empty()) {
- for (std::string const& sPath : this->UicSearchPaths) {
- testFiles.push_back((sPath + "/").append(searchFileFull));
- }
- }
- }
- }
-
- // Search for the .ui file!
- for (std::string const& testFile : testFiles) {
- if (cmSystemTools::FileExists(testFile.c_str())) {
- absFile = cmSystemTools::GetRealPath(testFile);
- success = true;
- break;
- }
- }
-
- // Log error
- if (!success) {
- std::string emsg = "Could not find ";
- emsg += cmQtAutoGen::Quoted(searchFile);
- emsg += " in\n";
- for (std::string const& testFile : testFiles) {
- emsg += " ";
- emsg += cmQtAutoGen::Quoted(testFile);
- emsg += "\n";
- }
- this->LogFileError(cmQtAutoGen::UIC, sourceFile, emsg);
- }
-
- return success;
+ std::lock_guard<std::mutex> mocLock(JobsMutex_);
+ MocAutoFileUpdated_ = true;
}
-bool cmQtAutoGeneratorMocUic::UicGenerateAll()
+void cmQtAutoGeneratorMocUic::MocGenerateCompilation()
{
- if (!this->UicEnabled()) {
- return true;
- }
-
- // Look for name collisions in included uic files
- {
- bool collision = false;
- std::map<std::string, std::vector<UicJob const*>> collisions;
- for (auto const& job : this->UicJobs) {
- auto& list = collisions[job->IncludeString];
- if (!list.empty()) {
- collision = true;
- }
- list.push_back(job.get());
- }
- if (collision) {
- std::string emsg =
- "Included uic files with the same name will be "
- "generated from different sources.\n"
- "Consider to\n"
- " - add a directory prefix to a \"ui_<NAME>.h\" include "
- "(e.g \"sub/ui_<NAME>.h\")\n"
- " - rename the <NAME>.ui file(s) and adjust the \"ui_<NAME>.h\" "
- "include(s)\n"
- "Include conflicts\n"
- "-----------------\n";
- const auto& colls = collisions;
- for (auto const& coll : colls) {
- if (coll.second.size() > 1) {
- emsg += cmQtAutoGen::Quoted(coll.first);
- emsg += " included in\n";
- for (const UicJob* job : coll.second) {
- emsg += " - ";
- emsg += cmQtAutoGen::Quoted(job->Includer);
- emsg += "\n";
- }
- emsg += "would be generated from\n";
- for (const UicJob* job : coll.second) {
- emsg += " - ";
- emsg += cmQtAutoGen::Quoted(job->SourceFile);
- emsg += "\n";
- }
+ std::lock_guard<std::mutex> mocLock(JobsMutex_);
+ if (!JobThreadsAbort_ && Moc().Enabled) {
+ // Compose mocs compilation file content
+ {
+ std::string content =
+ "// This file is autogenerated. Changes will be overwritten.\n";
+ if (MocAutoFiles_.empty()) {
+ // Placeholder content
+ content += "// No files found that require moc or the moc files are "
+ "included\n";
+ content += "enum some_compilers { need_more_than_nothing };\n";
+ } else {
+ // Valid content
+ for (std::string const& mocfile : MocAutoFiles_) {
+ content += "#include \"";
+ content += mocfile;
+ content += "\"\n";
}
}
- this->LogError(cmQtAutoGen::UIC, emsg);
- return false;
- }
- }
-
- // Generate ui header files
- for (const auto& item : this->UicJobs) {
- if (!this->UicGenerateFile(*item)) {
- return false;
- }
- }
-
- return true;
-}
-
-/**
- * @return True on success
- */
-bool cmQtAutoGeneratorMocUic::UicGenerateFile(const UicJob& uicJob)
-{
- bool success = true;
-
- std::string const uicFileAbs = cmSystemTools::CollapseCombinedPath(
- this->AutogenBuildDir, uicJob.BuildFileRel);
-
- bool generate = false;
- std::string generateReason;
- if (!generate && !cmSystemTools::FileExists(uicFileAbs.c_str())) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(uicFileAbs);
- generateReason += " from its source file ";
- generateReason += cmQtAutoGen::Quoted(uicJob.SourceFile);
- generateReason += " because it doesn't exist";
- }
- generate = true;
- }
- if (!generate && this->UicSettingsChanged) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(uicFileAbs);
- generateReason += " from ";
- generateReason += cmQtAutoGen::Quoted(uicJob.SourceFile);
- generateReason += " because the UIC settings changed";
- }
- generate = true;
- }
- if (!generate) {
- std::string error;
- if (FileIsOlderThan(uicFileAbs, uicJob.SourceFile, &error)) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(uicFileAbs);
- generateReason += " because it's older than its source file ";
- generateReason += cmQtAutoGen::Quoted(uicJob.SourceFile);
- }
- generate = true;
- } else {
- if (!error.empty()) {
- this->LogError(cmQtAutoGen::UIC, error);
- success = false;
- }
- }
- }
- if (generate) {
- // Log
- if (this->GetVerbose()) {
- this->LogBold("Generating UIC header " + uicJob.BuildFileRel);
- this->LogInfo(cmQtAutoGen::UIC, generateReason);
- }
- // Make sure the parent directory exists
- if (this->MakeParentDirectory(cmQtAutoGen::UIC, uicFileAbs)) {
- // Compose uic command
- std::vector<std::string> cmd;
- cmd.push_back(this->UicExecutable);
- {
- std::vector<std::string> allOpts = this->UicTargetOptions;
- auto optionIt = this->UicOptions.find(uicJob.SourceFile);
- if (optionIt != this->UicOptions.end()) {
- cmQtAutoGen::UicMergeOptions(allOpts, optionIt->second,
- (this->QtVersionMajor == 5));
+ std::string const& compRel = Moc().CompFileRel;
+ std::string const& compAbs = Moc().CompFileAbs;
+ if (FileSys().FileDiffers(compAbs, content)) {
+ // Actually write mocs compilation file
+ if (Log().Verbose()) {
+ Log().Info(GeneratorT::MOC, "Generating MOC compilation " + compRel);
}
- cmd.insert(cmd.end(), allOpts.begin(), allOpts.end());
- }
- cmd.push_back("-o");
- cmd.push_back(uicFileAbs);
- cmd.push_back(uicJob.SourceFile);
-
- std::string output;
- if (this->RunCommand(cmd, output)) {
- // Success
- } else {
- // Command failed
- {
- std::string emsg = "uic failed for\n ";
- emsg += cmQtAutoGen::Quoted(uicJob.SourceFile);
- emsg += "\nincluded by\n ";
- emsg += cmQtAutoGen::Quoted(uicJob.Includer);
- this->LogCommandError(cmQtAutoGen::UIC, emsg, cmd, output);
+ if (!FileSys().FileWrite(GeneratorT::MOC, compAbs, content)) {
+ Log().ErrorFile(GeneratorT::MOC, compAbs,
+ "mocs compilation file writing failed");
+ RegisterJobError();
+ return;
}
- cmSystemTools::RemoveFile(uicFileAbs);
- success = false;
+ } else if (MocAutoFileUpdated_) {
+ // Only touch mocs compilation file
+ if (Log().Verbose()) {
+ Log().Info(GeneratorT::MOC, "Touching mocs compilation " + compRel);
+ }
+ FileSys().Touch(compAbs);
}
- } else {
- // Parent directory creation failed
- success = false;
}
}
- return success;
-}
-
-/**
- * @brief Tries to find the header file to the given file base path by
- * appending different header extensions
- * @return True on success
- */
-bool cmQtAutoGeneratorMocUic::FindHeader(std::string& header,
- std::string const& testBasePath) const
-{
- for (std::string const& ext : this->HeaderExtensions) {
- std::string testFilePath(testBasePath);
- testFilePath.push_back('.');
- testFilePath += ext;
- if (cmSystemTools::FileExists(testFilePath.c_str())) {
- header = testFilePath;
- return true;
- }
- }
- return false;
}
diff --git a/Source/cmQtAutoGeneratorMocUic.h b/Source/cmQtAutoGeneratorMocUic.h
index d510939..215e25a 100644
--- a/Source/cmQtAutoGeneratorMocUic.h
+++ b/Source/cmQtAutoGeneratorMocUic.h
@@ -8,188 +8,434 @@
#include "cmFilePathChecksum.h"
#include "cmQtAutoGen.h"
#include "cmQtAutoGenerator.h"
+#include "cmUVHandlePtr.h"
+#include "cm_uv.h"
#include "cmsys/RegularExpression.hxx"
+#include <algorithm>
+#include <condition_variable>
+#include <cstddef>
+#include <deque>
#include <map>
#include <memory> // IWYU pragma: keep
+#include <mutex>
#include <set>
#include <string>
+#include <thread>
#include <vector>
class cmMakefile;
+// @brief AUTOMOC and AUTOUIC generator
class cmQtAutoGeneratorMocUic : public cmQtAutoGenerator
{
CM_DISABLE_COPY(cmQtAutoGeneratorMocUic)
public:
cmQtAutoGeneratorMocUic();
+ ~cmQtAutoGeneratorMocUic() override;
-private:
+public:
// -- Types
+ class WorkerT;
/// @brief Search key plus regular expression pair
- struct KeyRegExp
+ ///
+ struct KeyExpT
{
- KeyRegExp() = default;
+ KeyExpT() = default;
- KeyRegExp(const char* key, const char* regExp)
+ KeyExpT(const char* key, const char* exp)
: Key(key)
- , RegExp(regExp)
+ , Exp(exp)
{
}
- KeyRegExp(std::string const& key, std::string const& regExp)
+ KeyExpT(std::string const& key, std::string const& exp)
: Key(key)
- , RegExp(regExp)
+ , Exp(exp)
{
}
std::string Key;
- cmsys::RegularExpression RegExp;
+ cmsys::RegularExpression Exp;
};
- /// @brief Source file job
- struct SourceJob
+ /// @brief Common settings
+ ///
+ class BaseSettingsT
{
- bool Moc = false;
- bool Uic = false;
+ CM_DISABLE_COPY(BaseSettingsT)
+ public:
+ // -- Volatile methods
+ BaseSettingsT(FileSystem* fileSystem)
+ : MultiConfig(MultiConfigT::WRAPPER)
+ , IncludeProjectDirsBefore(false)
+ , QtVersionMajor(4)
+ , NumThreads(1)
+ , FileSys(fileSystem)
+ {
+ }
+
+ // -- Const methods
+ std::string AbsoluteBuildPath(std::string const& relativePath) const;
+ bool FindHeader(std::string& header,
+ std::string const& testBasePath) const;
+
+ // -- Attributes
+ // - Config
+ std::string ConfigSuffix;
+ MultiConfigT MultiConfig;
+ bool IncludeProjectDirsBefore;
+ unsigned int QtVersionMajor;
+ unsigned int NumThreads;
+ // - Directories
+ std::string ProjectSourceDir;
+ std::string ProjectBinaryDir;
+ std::string CurrentSourceDir;
+ std::string CurrentBinaryDir;
+ std::string AutogenBuildDir;
+ std::string AutogenIncludeDirRel;
+ std::string AutogenIncludeDirAbs;
+ // - Files
+ cmFilePathChecksum FilePathChecksum;
+ std::vector<std::string> HeaderExtensions;
+ // - File system
+ FileSystem* FileSys;
};
- /// @brief MOC job
- struct MocJobAuto
+ /// @brief Moc settings
+ ///
+ class MocSettingsT
{
- std::string SourceFile;
- std::string BuildFileRel;
- std::set<std::string> Depends;
+ CM_DISABLE_COPY(MocSettingsT)
+ public:
+ MocSettingsT(FileSystem* fileSys)
+ : FileSys(fileSys)
+ {
+ }
+
+ // -- Const methods
+ bool skipped(std::string const& fileName) const;
+ std::string FindMacro(std::string const& content) const;
+ std::string MacrosString() const;
+ std::string FindIncludedFile(std::string const& sourcePath,
+ std::string const& includeString) const;
+ void FindDependencies(std::string const& content,
+ std::set<std::string>& depends) const;
+
+ // -- Attributes
+ bool Enabled = false;
+ bool SettingsChanged = false;
+ bool RelaxedMode = false;
+ std::string Executable;
+ std::string CompFileRel;
+ std::string CompFileAbs;
+ std::string PredefsFileRel;
+ std::string PredefsFileAbs;
+ std::set<std::string> SkipList;
+ std::vector<std::string> IncludePaths;
+ std::vector<std::string> Includes;
+ std::vector<std::string> Definitions;
+ std::vector<std::string> Options;
+ std::vector<std::string> AllOptions;
+ std::vector<std::string> PredefsCmd;
+ std::vector<KeyExpT> DependFilters;
+ std::vector<KeyExpT> MacroFilters;
+ cmsys::RegularExpression RegExpInclude;
+ // - File system
+ FileSystem* FileSys;
};
- /// @brief MOC job
- struct MocJobIncluded : MocJobAuto
+ /// @brief Uic settings
+ ///
+ class UicSettingsT
{
- bool DependsValid = false;
- std::string Includer;
+ CM_DISABLE_COPY(UicSettingsT)
+ public:
+ UicSettingsT() = default;
+ // -- Const methods
+ bool skipped(std::string const& fileName) const;
+
+ // -- Attributes
+ bool Enabled = false;
+ bool SettingsChanged = false;
+ std::string Executable;
+ std::set<std::string> SkipList;
+ std::vector<std::string> TargetOptions;
+ std::map<std::string, std::vector<std::string>> Options;
+ std::vector<std::string> SearchPaths;
+ cmsys::RegularExpression RegExpInclude;
+ };
+
+ /// @brief Abstract job class for threaded processing
+ ///
+ class JobT
+ {
+ CM_DISABLE_COPY(JobT)
+ public:
+ JobT() = default;
+ virtual ~JobT() = default;
+ // -- Abstract processing interface
+ virtual void Process(WorkerT& wrk) = 0;
+ };
+
+ /// @brief Deleter for classes derived from Job
+ ///
+ struct JobDeleterT
+ {
+ void operator()(JobT* job);
+ };
+
+ // Job management types
+ typedef std::unique_ptr<JobT, JobDeleterT> JobHandleT;
+ typedef std::deque<JobHandleT> JobQueueT;
+
+ /// @brief Parse source job
+ ///
+ class JobParseT : public JobT
+ {
+ public:
+ JobParseT(std::string&& fileName, bool moc, bool uic, bool header = false)
+ : FileName(std::move(fileName))
+ , AutoMoc(moc)
+ , AutoUic(uic)
+ , Header(header)
+ {
+ }
+
+ private:
+ struct MetaT
+ {
+ std::string Content;
+ std::string FileDir;
+ std::string FileBase;
+ };
+
+ void Process(WorkerT& wrk) override;
+ bool ParseMocSource(WorkerT& wrk, MetaT const& meta);
+ bool ParseMocHeader(WorkerT& wrk, MetaT const& meta);
+ std::string MocStringHeaders(WorkerT& wrk,
+ std::string const& fileBase) const;
+ std::string MocFindIncludedHeader(WorkerT& wrk,
+ std::string const& includerDir,
+ std::string const& includeBase);
+ bool ParseUic(WorkerT& wrk, MetaT const& meta);
+ bool ParseUicInclude(WorkerT& wrk, MetaT const& meta,
+ std::string&& includeString);
+ std::string UicFindIncludedFile(WorkerT& wrk, MetaT const& meta,
+ std::string const& includeString);
+
+ private:
+ std::string FileName;
+ bool AutoMoc = false;
+ bool AutoUic = false;
+ bool Header = false;
+ };
+
+ /// @brief Generate moc_predefs
+ ///
+ class JobMocPredefsT : public JobT
+ {
+ private:
+ void Process(WorkerT& wrk) override;
+ };
+
+ /// @brief Moc a file job
+ ///
+ class JobMocT : public JobT
+ {
+ public:
+ JobMocT(std::string&& sourceFile, std::string const& includerFile,
+ std::string&& includeString)
+ : SourceFile(std::move(sourceFile))
+ , IncluderFile(includerFile)
+ , IncludeString(std::move(includeString))
+ {
+ }
+
+ void FindDependencies(WorkerT& wrk, std::string const& content);
+
+ private:
+ void Process(WorkerT& wrk) override;
+ bool UpdateRequired(WorkerT& wrk);
+ void GenerateMoc(WorkerT& wrk);
+
+ public:
+ std::string SourceFile;
+ std::string IncluderFile;
std::string IncludeString;
+ std::string BuildFile;
+ bool DependsValid = false;
+ std::set<std::string> Depends;
};
- /// @brief UIC job
- struct UicJob
+ /// @brief Uic a file job
+ ///
+ class JobUicT : public JobT
{
+ public:
+ JobUicT(std::string&& sourceFile, std::string const& includerFile,
+ std::string&& includeString)
+ : SourceFile(std::move(sourceFile))
+ , IncluderFile(includerFile)
+ , IncludeString(std::move(includeString))
+ {
+ }
+
+ private:
+ void Process(WorkerT& wrk) override;
+ bool UpdateRequired(WorkerT& wrk);
+ void GenerateUic(WorkerT& wrk);
+
+ public:
std::string SourceFile;
- std::string BuildFileRel;
- std::string Includer;
+ std::string IncluderFile;
std::string IncludeString;
+ std::string BuildFile;
};
- // -- Initialization
- bool InitInfoFile(cmMakefile* makefile);
+ /// @brief Worker Thread
+ ///
+ class WorkerT
+ {
+ CM_DISABLE_COPY(WorkerT)
+ public:
+ WorkerT(cmQtAutoGeneratorMocUic* gen, uv_loop_t* uvLoop);
+ ~WorkerT();
+
+ // -- Const accessors
+ cmQtAutoGeneratorMocUic& Gen() const { return *Gen_; }
+ Logger& Log() const { return Gen_->Log(); }
+ FileSystem& FileSys() const { return Gen_->FileSys(); }
+ const BaseSettingsT& Base() const { return Gen_->Base(); }
+ const MocSettingsT& Moc() const { return Gen_->Moc(); }
+ const UicSettingsT& Uic() const { return Gen_->Uic(); }
- // -- Settings file
- void SettingsFileRead(cmMakefile* makefile);
- bool SettingsFileWrite();
- bool SettingsChanged() const
+ // -- Log info
+ void LogInfo(GeneratorT genType, std::string const& message) const;
+ // -- Log warning
+ void LogWarning(GeneratorT genType, std::string const& message) const;
+ void LogFileWarning(GeneratorT genType, std::string const& filename,
+ std::string const& message) const;
+ // -- Log error
+ void LogError(GeneratorT genType, std::string const& message) const;
+ void LogFileError(GeneratorT genType, std::string const& filename,
+ std::string const& message) const;
+ void LogCommandError(GeneratorT genType, std::string const& message,
+ std::vector<std::string> const& command,
+ std::string const& output) const;
+
+ // -- External processes
+ /// @brief Verbose logging version
+ bool RunProcess(GeneratorT genType, ProcessResultT& result,
+ std::vector<std::string> const& command);
+
+ private:
+ /// @brief Thread main loop
+ void Loop();
+
+ // -- Libuv callbacks
+ static void UVProcessStart(uv_async_t* handle);
+ void UVProcessFinished();
+
+ private:
+ // -- Generator
+ cmQtAutoGeneratorMocUic* Gen_;
+ // -- Job handle
+ JobHandleT JobHandle_;
+ // -- Process management
+ std::mutex ProcessMutex_;
+ cm::uv_async_ptr ProcessRequest_;
+ std::condition_variable ProcessCondition_;
+ std::unique_ptr<ReadOnlyProcessT> Process_;
+ // -- System thread
+ std::thread Thread_;
+ };
+
+ /// @brief Processing stage
+ enum class StageT
{
- return (this->MocSettingsChanged || this->UicSettingsChanged);
- }
-
- // -- Central processing
- bool Process(cmMakefile* makefile) override;
-
- // -- Source parsing
- bool ParseSourceFile(std::string const& absFilename, const SourceJob& job);
- bool ParseHeaderFile(std::string const& absFilename, const SourceJob& job);
- bool ParsePostprocess();
-
- // -- Moc
- bool MocEnabled() const { return !this->MocExecutable.empty(); }
- bool MocSkip(std::string const& absFilename) const;
- bool MocRequired(std::string const& contentText,
- std::string* macroName = nullptr);
- // Moc strings
- std::string MocStringMacros() const;
- std::string MocStringHeaders(std::string const& fileBase) const;
- std::string MocFindIncludedHeader(std::string const& sourcePath,
- std::string const& includeBase) const;
- bool MocFindIncludedFile(std::string& absFile, std::string const& sourceFile,
- std::string const& includeString) const;
- // Moc depends
- bool MocDependFilterPush(std::string const& key, std::string const& regExp);
- void MocFindDepends(std::string const& absFilename,
- std::string const& contentText,
- std::set<std::string>& depends);
- // Moc
- bool MocParseSourceContent(std::string const& absFilename,
- std::string const& contentText);
- void MocParseHeaderContent(std::string const& absFilename,
- std::string const& contentText);
-
- bool MocGenerateAll();
- bool MocGenerateFile(const MocJobAuto& mocJob, bool* generated = nullptr);
-
- // -- Uic
- bool UicEnabled() const { return !this->UicExecutable.empty(); }
- bool UicSkip(std::string const& absFilename) const;
- bool UicParseContent(std::string const& fileName,
- std::string const& contentText);
- bool UicFindIncludedFile(std::string& absFile, std::string const& sourceFile,
- std::string const& includeString);
- bool UicGenerateAll();
- bool UicGenerateFile(const UicJob& uicJob);
-
- // -- Utility
- bool FindHeader(std::string& header, std::string const& testBasePath) const;
-
- // -- Meta
- std::string ConfigSuffix;
- cmQtAutoGen::MultiConfig MultiConfig;
+ SETTINGS_READ,
+ CREATE_DIRECTORIES,
+ PARSE_SOURCES,
+ PARSE_HEADERS,
+ MOC_PREDEFS,
+ MOC_PROCESS,
+ MOCS_COMPILATION,
+ UIC_PROCESS,
+ SETTINGS_WRITE,
+ FINISH,
+ END
+ };
+
+ // -- Const settings interface
+ const BaseSettingsT& Base() const { return this->Base_; }
+ const MocSettingsT& Moc() const { return this->Moc_; }
+ const UicSettingsT& Uic() const { return this->Uic_; }
+
+ // -- Worker thread interface
+ void WorkerSwapJob(JobHandleT& jobHandle);
+ // -- Parallel job processing interface
+ void ParallelRegisterJobError();
+ bool ParallelJobPushMoc(JobHandleT& jobHandle);
+ bool ParallelJobPushUic(JobHandleT& jobHandle);
+ bool ParallelMocIncluded(std::string const& sourceFile);
+ void ParallelMocAutoRegister(std::string const& mocFile);
+ void ParallelMocAutoUpdated();
+
+private:
+ // -- Abstract processing interface
+ bool Init(cmMakefile* makefile) override;
+ bool Process() override;
+ // -- Process stage
+ static void UVPollStage(uv_async_t* handle);
+ void PollStage();
+ void SetStage(StageT stage);
+ // -- Settings file
+ void SettingsFileRead();
+ void SettingsFileWrite();
+ // -- Thread processing
+ bool ThreadsStartJobs(JobQueueT& queue);
+ bool ThreadsJobsDone();
+ void ThreadsStop();
+ void RegisterJobError();
+ // -- Generation
+ void CreateDirectories();
+ void MocGenerateCompilation();
+
+private:
// -- Settings
- bool IncludeProjectDirsBefore;
- std::string SettingsFile;
- std::string SettingsStringMoc;
- std::string SettingsStringUic;
- // -- Directories
- std::string ProjectSourceDir;
- std::string ProjectBinaryDir;
- std::string CurrentSourceDir;
- std::string CurrentBinaryDir;
- std::string AutogenBuildDir;
- std::string AutogenIncludeDir;
- // -- Qt environment
- unsigned long QtVersionMajor;
- std::string MocExecutable;
- std::string UicExecutable;
- // -- File lists
- std::map<std::string, SourceJob> HeaderJobs;
- std::map<std::string, SourceJob> SourceJobs;
- std::vector<std::string> HeaderExtensions;
- cmFilePathChecksum FilePathChecksum;
- // -- Moc
- bool MocSettingsChanged;
- bool MocPredefsChanged;
- bool MocRelaxedMode;
- std::string MocCompFileRel;
- std::string MocCompFileAbs;
- std::string MocPredefsFileRel;
- std::string MocPredefsFileAbs;
- std::vector<std::string> MocSkipList;
- std::vector<std::string> MocIncludePaths;
- std::vector<std::string> MocIncludes;
- std::vector<std::string> MocDefinitions;
- std::vector<std::string> MocOptions;
- std::vector<std::string> MocAllOptions;
- std::vector<std::string> MocPredefsCmd;
- std::vector<KeyRegExp> MocDependFilters;
- std::vector<KeyRegExp> MocMacroFilters;
- cmsys::RegularExpression MocRegExpInclude;
- std::vector<std::unique_ptr<MocJobIncluded>> MocJobsIncluded;
- std::vector<std::unique_ptr<MocJobAuto>> MocJobsAuto;
- // -- Uic
- bool UicSettingsChanged;
- std::vector<std::string> UicSkipList;
- std::vector<std::string> UicTargetOptions;
- std::map<std::string, std::vector<std::string>> UicOptions;
- std::vector<std::string> UicSearchPaths;
- cmsys::RegularExpression UicRegExpInclude;
- std::vector<std::unique_ptr<UicJob>> UicJobs;
+ BaseSettingsT Base_;
+ MocSettingsT Moc_;
+ UicSettingsT Uic_;
+ // -- Progress
+ StageT Stage_;
+ // -- Job queues
+ std::mutex JobsMutex_;
+ struct
+ {
+ JobQueueT Sources;
+ JobQueueT Headers;
+ JobQueueT MocPredefs;
+ JobQueueT Moc;
+ JobQueueT Uic;
+ } JobQueues_;
+ JobQueueT JobQueue_;
+ std::size_t volatile JobsRemain_;
+ bool volatile JobError_;
+ bool volatile JobThreadsAbort_;
+ std::condition_variable JobsConditionRead_;
+ // -- Moc meta
+ std::set<std::string> MocIncludedStrings_;
+ std::set<std::string> MocIncludedFiles_;
+ std::set<std::string> MocAutoFiles_;
+ bool volatile MocAutoFileUpdated_;
+ // -- Settings file
+ std::string SettingsFile_;
+ std::string SettingsStringMoc_;
+ std::string SettingsStringUic_;
+ // -- Threads and loops
+ std::vector<std::unique_ptr<WorkerT>> Workers_;
};
#endif
diff --git a/Source/cmQtAutoGeneratorRcc.cxx b/Source/cmQtAutoGeneratorRcc.cxx
index 3c9f1a8..e8ff75a 100644
--- a/Source/cmQtAutoGeneratorRcc.cxx
+++ b/Source/cmQtAutoGeneratorRcc.cxx
@@ -6,22 +6,30 @@
#include "cmAlgorithms.h"
#include "cmCryptoHash.h"
#include "cmMakefile.h"
-#include "cmOutputConverter.h"
#include "cmSystemTools.h"
+#include "cmUVHandlePtr.h"
-// -- Static variables
-
-static const char* SettingsKeyRcc = "ARCC_SETTINGS_HASH";
+#include <functional>
// -- Class methods
cmQtAutoGeneratorRcc::cmQtAutoGeneratorRcc()
- : MultiConfig(cmQtAutoGen::WRAP)
- , SettingsChanged(false)
+ : SettingsChanged_(false)
+ , MultiConfig_(MultiConfigT::WRAPPER)
+ , Stage_(StageT::SETTINGS_READ)
+ , Error_(false)
+ , Generate_(false)
+ , BuildFileChanged_(false)
{
+ // Initialize libuv asynchronous iteration request
+ UVRequest().init(*UVLoop(), &cmQtAutoGeneratorRcc::UVPollStage, this);
}
-bool cmQtAutoGeneratorRcc::InfoFileRead(cmMakefile* makefile)
+cmQtAutoGeneratorRcc::~cmQtAutoGeneratorRcc()
+{
+}
+
+bool cmQtAutoGeneratorRcc::Init(cmMakefile* makefile)
{
// Utility lambdas
auto InfoGet = [makefile](const char* key) {
@@ -37,7 +45,7 @@ bool cmQtAutoGeneratorRcc::InfoFileRead(cmMakefile* makefile)
{
std::string keyConf = key;
keyConf += '_';
- keyConf += this->GetInfoConfig();
+ keyConf += InfoConfig();
valueConf = makefile->GetDefinition(keyConf);
}
if (valueConf == nullptr) {
@@ -53,79 +61,180 @@ bool cmQtAutoGeneratorRcc::InfoFileRead(cmMakefile* makefile)
};
// -- Read info file
- if (!makefile->ReadListFile(this->GetInfoFile().c_str())) {
- this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(),
- "File processing failed");
+ if (!makefile->ReadListFile(InfoFile().c_str())) {
+ Log().ErrorFile(GeneratorT::RCC, InfoFile(), "File processing failed");
return false;
}
// -- Meta
- this->MultiConfig =
- cmQtAutoGen::MultiConfigType(InfoGet("ARCC_MULTI_CONFIG"));
- this->ConfigSuffix = InfoGetConfig("ARCC_CONFIG_SUFFIX");
- if (this->ConfigSuffix.empty()) {
- this->ConfigSuffix = "_";
- this->ConfigSuffix += this->GetInfoConfig();
+ MultiConfig_ = MultiConfigType(InfoGet("ARCC_MULTI_CONFIG"));
+ ConfigSuffix_ = InfoGetConfig("ARCC_CONFIG_SUFFIX");
+ if (ConfigSuffix_.empty()) {
+ ConfigSuffix_ = "_";
+ ConfigSuffix_ += InfoConfig();
}
- this->SettingsFile = InfoGetConfig("ARCC_SETTINGS_FILE");
+ SettingsFile_ = InfoGetConfig("ARCC_SETTINGS_FILE");
// - Files and directories
- this->ProjectSourceDir = InfoGet("ARCC_CMAKE_SOURCE_DIR");
- this->ProjectBinaryDir = InfoGet("ARCC_CMAKE_BINARY_DIR");
- this->CurrentSourceDir = InfoGet("ARCC_CMAKE_CURRENT_SOURCE_DIR");
- this->CurrentBinaryDir = InfoGet("ARCC_CMAKE_CURRENT_BINARY_DIR");
- this->AutogenBuildDir = InfoGet("ARCC_BUILD_DIR");
+ AutogenBuildDir_ = InfoGet("ARCC_BUILD_DIR");
// - Qt environment
- this->RccExecutable = InfoGet("ARCC_RCC_EXECUTABLE");
- this->RccListOptions = InfoGetList("ARCC_RCC_LIST_OPTIONS");
+ RccExecutable_ = InfoGet("ARCC_RCC_EXECUTABLE");
+ RccListOptions_ = InfoGetList("ARCC_RCC_LIST_OPTIONS");
// - Job
- this->QrcFile = InfoGet("ARCC_SOURCE");
- this->RccFile = InfoGet("ARCC_OUTPUT");
- this->Options = InfoGetConfigList("ARCC_OPTIONS");
- this->Inputs = InfoGetList("ARCC_INPUTS");
+ QrcFile_ = InfoGet("ARCC_SOURCE");
+ QrcFileName_ = cmSystemTools::GetFilenameName(QrcFile_);
+ QrcFileDir_ = cmSystemTools::GetFilenamePath(QrcFile_);
+ RccFile_ = InfoGet("ARCC_OUTPUT");
+ Options_ = InfoGetConfigList("ARCC_OPTIONS");
+ Inputs_ = InfoGetList("ARCC_INPUTS");
// - Validity checks
- if (this->SettingsFile.empty()) {
- this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(),
- "Settings file name missing");
+ if (SettingsFile_.empty()) {
+ Log().ErrorFile(GeneratorT::RCC, InfoFile(), "Settings file name missing");
return false;
}
- if (this->AutogenBuildDir.empty()) {
- this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(),
- "Autogen build directory missing");
+ if (AutogenBuildDir_.empty()) {
+ Log().ErrorFile(GeneratorT::RCC, InfoFile(),
+ "Autogen build directory missing");
return false;
}
- if (this->RccExecutable.empty()) {
- this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(),
- "rcc executable missing");
+ if (RccExecutable_.empty()) {
+ Log().ErrorFile(GeneratorT::RCC, InfoFile(), "rcc executable missing");
return false;
}
- if (this->QrcFile.empty()) {
- this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(),
- "rcc input file missing");
+ if (QrcFile_.empty()) {
+ Log().ErrorFile(GeneratorT::RCC, InfoFile(), "rcc input file missing");
return false;
}
- if (this->RccFile.empty()) {
- this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(),
- "rcc output file missing");
+ if (RccFile_.empty()) {
+ Log().ErrorFile(GeneratorT::RCC, InfoFile(), "rcc output file missing");
return false;
}
// Init derived information
// ------------------------
- // Init file path checksum generator
- this->FilePathChecksum.setupParentDirs(
- this->CurrentSourceDir, this->CurrentBinaryDir, this->ProjectSourceDir,
- this->ProjectBinaryDir);
+ // Compute rcc output file name
+ {
+ std::string suffix;
+ switch (MultiConfig_) {
+ case MultiConfigT::SINGLE:
+ break;
+ case MultiConfigT::WRAPPER:
+ suffix = "_CMAKE";
+ suffix += ConfigSuffix_;
+ suffix += "_";
+ break;
+ case MultiConfigT::MULTI:
+ suffix = ConfigSuffix_;
+ break;
+ }
+ RccFileBuild_ = AppendFilenameSuffix(RccFile_, suffix);
+ }
+
+ return true;
+}
+bool cmQtAutoGeneratorRcc::Process()
+{
+ // Run libuv event loop
+ UVRequest().send();
+ if (uv_run(UVLoop(), UV_RUN_DEFAULT) == 0) {
+ if (Error_) {
+ return false;
+ }
+ } else {
+ return false;
+ }
return true;
}
-void cmQtAutoGeneratorRcc::SettingsFileRead(cmMakefile* makefile)
+void cmQtAutoGeneratorRcc::UVPollStage(uv_async_t* handle)
+{
+ reinterpret_cast<cmQtAutoGeneratorRcc*>(handle->data)->PollStage();
+}
+
+void cmQtAutoGeneratorRcc::PollStage()
+{
+ switch (Stage_) {
+ // -- Initialize
+ case StageT::SETTINGS_READ:
+ SettingsFileRead();
+ SetStage(StageT::TEST_QRC_RCC_FILES);
+ break;
+
+ // -- Change detection
+ case StageT::TEST_QRC_RCC_FILES:
+ if (TestQrcRccFiles()) {
+ SetStage(StageT::GENERATE);
+ } else {
+ SetStage(StageT::TEST_RESOURCES_READ);
+ }
+ break;
+ case StageT::TEST_RESOURCES_READ:
+ if (TestResourcesRead()) {
+ SetStage(StageT::TEST_RESOURCES);
+ }
+ break;
+ case StageT::TEST_RESOURCES:
+ if (TestResources()) {
+ SetStage(StageT::GENERATE);
+ } else {
+ SetStage(StageT::TEST_INFO_FILE);
+ }
+ break;
+ case StageT::TEST_INFO_FILE:
+ TestInfoFile();
+ SetStage(StageT::GENERATE_WRAPPER);
+ break;
+
+ // -- Generation
+ case StageT::GENERATE:
+ GenerateParentDir();
+ SetStage(StageT::GENERATE_RCC);
+ break;
+ case StageT::GENERATE_RCC:
+ if (GenerateRcc()) {
+ SetStage(StageT::GENERATE_WRAPPER);
+ }
+ break;
+ case StageT::GENERATE_WRAPPER:
+ GenerateWrapper();
+ SetStage(StageT::SETTINGS_WRITE);
+ break;
+
+ // -- Finalize
+ case StageT::SETTINGS_WRITE:
+ SettingsFileWrite();
+ SetStage(StageT::FINISH);
+ break;
+ case StageT::FINISH:
+ // Clear all libuv handles
+ UVRequest().reset();
+ // Set highest END stage manually
+ Stage_ = StageT::END;
+ break;
+ case StageT::END:
+ break;
+ }
+}
+
+void cmQtAutoGeneratorRcc::SetStage(StageT stage)
+{
+ if (Error_) {
+ stage = StageT::FINISH;
+ }
+ // Only allow to increase the stage
+ if (Stage_ < stage) {
+ Stage_ = stage;
+ UVRequest().send();
+ }
+}
+
+void cmQtAutoGeneratorRcc::SettingsFileRead()
{
// Compose current settings strings
{
@@ -133,293 +242,375 @@ void cmQtAutoGeneratorRcc::SettingsFileRead(cmMakefile* makefile)
std::string const sep(" ~~~ ");
{
std::string str;
- str += this->RccExecutable;
+ str += RccExecutable_;
str += sep;
- str += cmJoin(this->RccListOptions, ";");
+ str += cmJoin(RccListOptions_, ";");
str += sep;
- str += this->QrcFile;
+ str += QrcFile_;
str += sep;
- str += this->RccFile;
+ str += RccFile_;
str += sep;
- str += cmJoin(this->Options, ";");
+ str += cmJoin(Options_, ";");
str += sep;
- str += cmJoin(this->Inputs, ";");
+ str += cmJoin(Inputs_, ";");
str += sep;
- this->SettingsString = crypt.HashString(str);
+ SettingsString_ = crypt.HashString(str);
}
}
// Read old settings
- if (makefile->ReadListFile(this->SettingsFile.c_str())) {
- {
- auto SMatch = [makefile](const char* key, std::string const& value) {
- return (value == makefile->GetSafeDefinition(key));
- };
- if (!SMatch(SettingsKeyRcc, this->SettingsString)) {
- this->SettingsChanged = true;
+ {
+ std::string content;
+ if (FileSys().FileRead(content, SettingsFile_)) {
+ SettingsChanged_ = (SettingsString_ != SettingsFind(content, "rcc"));
+ // In case any setting changed remove the old settings file.
+ // This triggers a full rebuild on the next run if the current
+ // build is aborted before writing the current settings in the end.
+ if (SettingsChanged_) {
+ FileSys().FileRemove(SettingsFile_);
}
+ } else {
+ SettingsChanged_ = true;
}
- // In case any setting changed remove the old settings file.
- // This triggers a full rebuild on the next run if the current
- // build is aborted before writing the current settings in the end.
- if (this->SettingsChanged) {
- cmSystemTools::RemoveFile(this->SettingsFile);
- }
- } else {
- // If the file could not be read re-generate everythiung.
- this->SettingsChanged = true;
}
}
-bool cmQtAutoGeneratorRcc::SettingsFileWrite()
+void cmQtAutoGeneratorRcc::SettingsFileWrite()
{
- bool success = true;
// Only write if any setting changed
- if (this->SettingsChanged) {
- if (this->GetVerbose()) {
- this->LogInfo(cmQtAutoGen::RCC, "Writing settings file " +
- cmQtAutoGen::Quoted(this->SettingsFile));
- }
- // Compose settings file content
- std::string settings;
- {
- auto SettingAppend = [&settings](const char* key,
- std::string const& value) {
- settings += "set(";
- settings += key;
- settings += " ";
- settings += cmOutputConverter::EscapeForCMake(value);
- settings += ")\n";
- };
- SettingAppend(SettingsKeyRcc, this->SettingsString);
+ if (SettingsChanged_) {
+ if (Log().Verbose()) {
+ Log().Info(GeneratorT::RCC,
+ "Writing settings file " + Quoted(SettingsFile_));
}
// Write settings file
- if (!this->FileWrite(cmQtAutoGen::RCC, this->SettingsFile, settings)) {
- this->LogFileError(cmQtAutoGen::RCC, this->SettingsFile,
- "Settings file writing failed");
+ std::string content = "rcc:";
+ content += SettingsString_;
+ content += '\n';
+ if (!FileSys().FileWrite(GeneratorT::RCC, SettingsFile_, content)) {
+ Log().ErrorFile(GeneratorT::RCC, SettingsFile_,
+ "Settings file writing failed");
// Remove old settings file to trigger a full rebuild on the next run
- cmSystemTools::RemoveFile(this->SettingsFile);
- success = false;
+ FileSys().FileRemove(SettingsFile_);
+ Error_ = true;
}
}
- return success;
}
-bool cmQtAutoGeneratorRcc::Process(cmMakefile* makefile)
+bool cmQtAutoGeneratorRcc::TestQrcRccFiles()
{
- // Read info file
- if (!this->InfoFileRead(makefile)) {
- return false;
+ // Do basic checks if rcc generation is required
+
+ // Test if the rcc output file exists
+ if (!FileSys().FileExists(RccFileBuild_)) {
+ if (Log().Verbose()) {
+ std::string reason = "Generating ";
+ reason += Quoted(RccFileBuild_);
+ reason += " from its source file ";
+ reason += Quoted(QrcFile_);
+ reason += " because it doesn't exist";
+ Log().Info(GeneratorT::RCC, reason);
+ }
+ Generate_ = true;
+ return Generate_;
}
- // Read latest settings
- this->SettingsFileRead(makefile);
- // Generate rcc file
- if (!this->RccGenerate()) {
- return false;
+
+ // Test if the settings changed
+ if (SettingsChanged_) {
+ if (Log().Verbose()) {
+ std::string reason = "Generating ";
+ reason += Quoted(RccFileBuild_);
+ reason += " from ";
+ reason += Quoted(QrcFile_);
+ reason += " because the RCC settings changed";
+ Log().Info(GeneratorT::RCC, reason);
+ }
+ Generate_ = true;
+ return Generate_;
}
- // Write latest settings
- if (!this->SettingsFileWrite()) {
- return false;
+
+ // Test if the rcc output file is older than the .qrc file
+ {
+ bool isOlder = false;
+ {
+ std::string error;
+ isOlder = FileSys().FileIsOlderThan(RccFileBuild_, QrcFile_, &error);
+ if (!error.empty()) {
+ Log().ErrorFile(GeneratorT::RCC, QrcFile_, error);
+ Error_ = true;
+ }
+ }
+ if (isOlder) {
+ if (Log().Verbose()) {
+ std::string reason = "Generating ";
+ reason += Quoted(RccFileBuild_);
+ reason += " because it is older than ";
+ reason += Quoted(QrcFile_);
+ Log().Info(GeneratorT::RCC, reason);
+ }
+ Generate_ = true;
+ }
}
- return true;
+
+ return Generate_;
}
-/**
- * @return True on success
- */
-bool cmQtAutoGeneratorRcc::RccGenerate()
+bool cmQtAutoGeneratorRcc::TestResourcesRead()
{
- bool success = true;
- bool rccGenerated = false;
-
- std::string rccFileAbs;
- {
- std::string suffix;
- switch (this->MultiConfig) {
- case cmQtAutoGen::SINGLE:
- break;
- case cmQtAutoGen::WRAP:
- suffix = "_CMAKE";
- suffix += this->ConfigSuffix;
- suffix += "_";
- break;
- case cmQtAutoGen::FULL:
- suffix = this->ConfigSuffix;
- break;
- }
- rccFileAbs = cmQtAutoGen::AppendFilenameSuffix(this->RccFile, suffix);
+ if (!Inputs_.empty()) {
+ // Inputs are known already
+ return true;
}
- std::string const rccFileRel = cmSystemTools::RelativePath(
- this->AutogenBuildDir.c_str(), rccFileAbs.c_str());
- // Check if regeneration is required
- bool generate = false;
- std::string generateReason;
- if (!cmSystemTools::FileExists(this->QrcFile)) {
- {
- std::string error = "Could not find the file\n ";
- error += cmQtAutoGen::Quoted(this->QrcFile);
- this->LogError(cmQtAutoGen::RCC, error);
+ if (!RccListOptions_.empty()) {
+ // Start a rcc list process and parse the output
+ if (Process_) {
+ // Process is running already
+ if (Process_->IsFinished()) {
+ // Process is finished
+ if (!ProcessResult_.error()) {
+ // Process success
+ std::string parseError;
+ if (!RccListParseOutput(ProcessResult_.StdOut, ProcessResult_.StdErr,
+ Inputs_, parseError)) {
+ Log().ErrorFile(GeneratorT::RCC, QrcFile_, parseError);
+ Error_ = true;
+ }
+ } else {
+ Log().ErrorFile(GeneratorT::RCC, QrcFile_,
+ ProcessResult_.ErrorMessage);
+ Error_ = true;
+ }
+ // Clean up
+ Process_.reset();
+ ProcessResult_.reset();
+ } else {
+ // Process is not finished, yet.
+ return false;
+ }
+ } else {
+ // Start a new process
+ // rcc prints relative entry paths when started in the directory of the
+ // qrc file with a pathless qrc file name argument.
+ // This is important because on Windows absolute paths returned by rcc
+ // might contain bad multibyte characters when the qrc file path
+ // contains non-ASCII pcharacters.
+ std::vector<std::string> cmd;
+ cmd.push_back(RccExecutable_);
+ cmd.insert(cmd.end(), RccListOptions_.begin(), RccListOptions_.end());
+ cmd.push_back(QrcFileName_);
+ // We're done here if the process fails to start
+ return !StartProcess(QrcFileDir_, cmd, false);
}
- success = false;
- }
- if (success && !generate && !cmSystemTools::FileExists(rccFileAbs.c_str())) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(rccFileAbs);
- generateReason += " from its source file ";
- generateReason += cmQtAutoGen::Quoted(this->QrcFile);
- generateReason += " because it doesn't exist";
+ } else {
+ // rcc does not support the --list command.
+ // Read the qrc file content and parse it.
+ std::string qrcContent;
+ if (FileSys().FileRead(GeneratorT::RCC, qrcContent, QrcFile_)) {
+ RccListParseContent(qrcContent, Inputs_);
}
- generate = true;
}
- if (success && !generate && this->SettingsChanged) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(rccFileAbs);
- generateReason += " from ";
- generateReason += cmQtAutoGen::Quoted(this->QrcFile);
- generateReason += " because the RCC settings changed";
- }
- generate = true;
+
+ if (!Inputs_.empty()) {
+ // Convert relative paths to absolute paths
+ RccListConvertFullPath(QrcFileDir_, Inputs_);
+ }
+
+ return true;
+}
+
+bool cmQtAutoGeneratorRcc::TestResources()
+{
+ if (Inputs_.empty()) {
+ return true;
}
- if (success && !generate) {
+ {
std::string error;
- if (FileIsOlderThan(rccFileAbs, this->QrcFile, &error)) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(rccFileAbs);
- generateReason += " because it is older than ";
- generateReason += cmQtAutoGen::Quoted(this->QrcFile);
+ for (std::string const& resFile : Inputs_) {
+ // Check if the resource file exists
+ if (!FileSys().FileExists(resFile)) {
+ error = "Could not find the resource file\n ";
+ error += Quoted(resFile);
+ error += '\n';
+ Log().ErrorFile(GeneratorT::RCC, QrcFile_, error);
+ Error_ = true;
+ break;
}
- generate = true;
- } else {
+ // Check if the resource file is newer than the build file
+ if (FileSys().FileIsOlderThan(RccFileBuild_, resFile, &error)) {
+ if (Log().Verbose()) {
+ std::string reason = "Generating ";
+ reason += Quoted(RccFileBuild_);
+ reason += " from ";
+ reason += Quoted(QrcFile_);
+ reason += " because it is older than ";
+ reason += Quoted(resFile);
+ Log().Info(GeneratorT::RCC, reason);
+ }
+ Generate_ = true;
+ break;
+ }
+ // Print error and break on demand
if (!error.empty()) {
- this->LogError(cmQtAutoGen::RCC, error);
- success = false;
+ Log().ErrorFile(GeneratorT::RCC, QrcFile_, error);
+ Error_ = true;
+ break;
}
}
}
- if (success && !generate) {
- // Acquire input file list
- std::vector<std::string> readFiles;
- std::vector<std::string> const* files = nullptr;
- if (!this->Inputs.empty()) {
- files = &this->Inputs;
- } else {
- // Read input file list from qrc file
+
+ return Generate_;
+}
+
+void cmQtAutoGeneratorRcc::TestInfoFile()
+{
+ // Test if the rcc output file is older than the info file
+ {
+ bool isOlder = false;
+ {
std::string error;
- if (cmQtAutoGen::RccListInputs(this->RccExecutable, this->RccListOptions,
- this->QrcFile, readFiles, &error)) {
- files = &readFiles;
- } else {
- this->LogFileError(cmQtAutoGen::RCC, this->QrcFile, error);
- success = false;
+ isOlder = FileSys().FileIsOlderThan(RccFileBuild_, InfoFile(), &error);
+ if (!error.empty()) {
+ Log().ErrorFile(GeneratorT::RCC, QrcFile_, error);
+ Error_ = true;
}
}
- // Test if any input file is newer than the build file
- if (files != nullptr) {
- std::string error;
- for (std::string const& resFile : *files) {
- if (!cmSystemTools::FileExists(resFile.c_str())) {
- error = "Could not find the file\n ";
- error += cmQtAutoGen::Quoted(resFile);
- error += "\nwhich is listed in\n ";
- error += cmQtAutoGen::Quoted(this->QrcFile);
- break;
- }
- if (FileIsOlderThan(rccFileAbs, resFile, &error)) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(rccFileAbs);
- generateReason += " from ";
- generateReason += cmQtAutoGen::Quoted(this->QrcFile);
- generateReason += " because it is older than ";
- generateReason += cmQtAutoGen::Quoted(resFile);
- }
- generate = true;
- break;
- }
- if (!error.empty()) {
- break;
- }
- }
- // Print error
- if (!error.empty()) {
- this->LogError(cmQtAutoGen::RCC, error);
- success = false;
+ if (isOlder) {
+ if (Log().Verbose()) {
+ std::string reason = "Touching ";
+ reason += Quoted(RccFileBuild_);
+ reason += " because it is older than ";
+ reason += Quoted(InfoFile());
+ Log().Info(GeneratorT::RCC, reason);
}
+ // Touch build file
+ FileSys().Touch(RccFileBuild_);
+ BuildFileChanged_ = true;
}
}
- // Regenerate on demand
- if (generate) {
- // Log
- if (this->GetVerbose()) {
- this->LogBold("Generating RCC source " + rccFileRel);
- this->LogInfo(cmQtAutoGen::RCC, generateReason);
- }
+}
- // Make sure the parent directory exists
- if (this->MakeParentDirectory(cmQtAutoGen::RCC, rccFileAbs)) {
- // Compose rcc command
- std::vector<std::string> cmd;
- cmd.push_back(this->RccExecutable);
- cmd.insert(cmd.end(), this->Options.begin(), this->Options.end());
- cmd.push_back("-o");
- cmd.push_back(rccFileAbs);
- cmd.push_back(this->QrcFile);
-
- std::string output;
- if (this->RunCommand(cmd, output)) {
- // Success
- rccGenerated = true;
+void cmQtAutoGeneratorRcc::GenerateParentDir()
+{
+ // Make sure the parent directory exists
+ if (!FileSys().MakeParentDirectory(GeneratorT::RCC, RccFileBuild_)) {
+ Error_ = true;
+ }
+}
+
+/**
+ * @return True when finished
+ */
+bool cmQtAutoGeneratorRcc::GenerateRcc()
+{
+ if (!Generate_) {
+ // Nothing to do
+ return true;
+ }
+
+ if (Process_) {
+ // Process is running already
+ if (Process_->IsFinished()) {
+ // Process is finished
+ if (!ProcessResult_.error()) {
+ // Process success
+ BuildFileChanged_ = true;
} else {
+ // Process failed
{
- std::string emsg = "rcc failed for\n ";
- emsg += cmQtAutoGen::Quoted(this->QrcFile);
- this->LogCommandError(cmQtAutoGen::RCC, emsg, cmd, output);
+ std::string emsg = "The rcc process failed to compile\n ";
+ emsg += Quoted(QrcFile_);
+ emsg += "\ninto\n ";
+ emsg += Quoted(RccFileBuild_);
+ if (ProcessResult_.error()) {
+ emsg += "\n";
+ emsg += ProcessResult_.ErrorMessage;
+ }
+ Log().ErrorCommand(GeneratorT::RCC, emsg, Process_->Setup().Command,
+ ProcessResult_.StdOut);
}
- cmSystemTools::RemoveFile(rccFileAbs);
- success = false;
+ FileSys().FileRemove(RccFileBuild_);
+ Error_ = true;
}
+ // Clean up
+ Process_.reset();
+ ProcessResult_.reset();
} else {
- // Parent directory creation failed
- success = false;
+ // Process is not finished, yet.
+ return false;
}
+ } else {
+ // Start a rcc process
+ std::vector<std::string> cmd;
+ cmd.push_back(RccExecutable_);
+ cmd.insert(cmd.end(), Options_.begin(), Options_.end());
+ cmd.push_back("-o");
+ cmd.push_back(RccFileBuild_);
+ cmd.push_back(QrcFile_);
+ // We're done here if the process fails to start
+ return !StartProcess(AutogenBuildDir_, cmd, true);
}
+ return true;
+}
+
+void cmQtAutoGeneratorRcc::GenerateWrapper()
+{
// Generate a wrapper source file on demand
- if (success && (this->MultiConfig == cmQtAutoGen::WRAP)) {
+ if (MultiConfig_ == MultiConfigT::WRAPPER) {
// Wrapper file name
- std::string const& wrapperFileAbs = this->RccFile;
- std::string const wrapperFileRel = cmSystemTools::RelativePath(
- this->AutogenBuildDir.c_str(), wrapperFileAbs.c_str());
+ std::string const& wrapperAbs = RccFile_;
// Wrapper file content
std::string content = "// This is an autogenerated configuration "
"wrapper file. Changes will be overwritten.\n"
"#include \"";
- content += cmSystemTools::GetFilenameName(rccFileRel);
+ content += cmSystemTools::GetFilenameName(RccFileBuild_);
content += "\"\n";
// Write content to file
- if (this->FileDiffers(wrapperFileAbs, content)) {
+ if (FileSys().FileDiffers(wrapperAbs, content)) {
// Write new wrapper file
- if (this->GetVerbose()) {
- this->LogBold("Generating RCC wrapper " + wrapperFileRel);
+ if (Log().Verbose()) {
+ Log().Info(GeneratorT::RCC, "Generating RCC wrapper " + wrapperAbs);
}
- if (!this->FileWrite(cmQtAutoGen::RCC, wrapperFileAbs, content)) {
- this->LogFileError(cmQtAutoGen::RCC, wrapperFileAbs,
- "rcc wrapper file writing failed");
- success = false;
+ if (!FileSys().FileWrite(GeneratorT::RCC, wrapperAbs, content)) {
+ Log().ErrorFile(GeneratorT::RCC, wrapperAbs,
+ "RCC wrapper file writing failed");
+ Error_ = true;
}
- } else if (rccGenerated) {
+ } else if (BuildFileChanged_) {
// Just touch the wrapper file
- if (this->GetVerbose()) {
- this->LogInfo(cmQtAutoGen::RCC,
- "Touching RCC wrapper " + wrapperFileRel);
+ if (Log().Verbose()) {
+ Log().Info(GeneratorT::RCC, "Touching RCC wrapper " + wrapperAbs);
}
- cmSystemTools::Touch(wrapperFileAbs, false);
+ FileSys().Touch(wrapperAbs);
}
}
+}
+
+bool cmQtAutoGeneratorRcc::StartProcess(
+ std::string const& workingDirectory, std::vector<std::string> const& command,
+ bool mergedOutput)
+{
+ // Log command
+ if (Log().Verbose()) {
+ std::string msg = "Running command:\n";
+ msg += QuotedCommand(command);
+ msg += '\n';
+ Log().Info(GeneratorT::RCC, msg);
+ }
- return success;
+ // Create process handler
+ Process_ = cm::make_unique<ReadOnlyProcessT>();
+ Process_->setup(&ProcessResult_, mergedOutput, command, workingDirectory);
+ // Start process
+ if (!Process_->start(UVLoop(),
+ std::bind(&cm::uv_async_ptr::send, &UVRequest()))) {
+ Log().ErrorFile(GeneratorT::RCC, QrcFile_, ProcessResult_.ErrorMessage);
+ Error_ = true;
+ // Clean up
+ Process_.reset();
+ ProcessResult_.reset();
+ return false;
+ }
+ return true;
}
diff --git a/Source/cmQtAutoGeneratorRcc.h b/Source/cmQtAutoGeneratorRcc.h
index 0e3f690..8a69c6c 100644
--- a/Source/cmQtAutoGeneratorRcc.h
+++ b/Source/cmQtAutoGeneratorRcc.h
@@ -5,52 +5,97 @@
#include "cmConfigure.h" // IWYU pragma: keep
-#include "cmFilePathChecksum.h"
#include "cmQtAutoGen.h"
#include "cmQtAutoGenerator.h"
+#include "cm_uv.h"
#include <string>
#include <vector>
class cmMakefile;
+// @brief AUTORCC generator
class cmQtAutoGeneratorRcc : public cmQtAutoGenerator
{
CM_DISABLE_COPY(cmQtAutoGeneratorRcc)
public:
cmQtAutoGeneratorRcc();
+ ~cmQtAutoGeneratorRcc() override;
private:
- // -- Initialization & settings
- bool InfoFileRead(cmMakefile* makefile);
- void SettingsFileRead(cmMakefile* makefile);
- bool SettingsFileWrite();
- // -- Central processing
- bool Process(cmMakefile* makefile) override;
- bool RccGenerate();
+ // -- Types
+ /// @brief Processing stage
+ enum class StageT
+ {
+ SETTINGS_READ,
+ TEST_QRC_RCC_FILES,
+ TEST_RESOURCES_READ,
+ TEST_RESOURCES,
+ TEST_INFO_FILE,
+ GENERATE,
+ GENERATE_RCC,
+ GENERATE_WRAPPER,
+ SETTINGS_WRITE,
+ FINISH,
+ END
+ };
+
+ // -- Abstract processing interface
+ bool Init(cmMakefile* makefile) override;
+ bool Process() override;
+ // -- Process stage
+ static void UVPollStage(uv_async_t* handle);
+ void PollStage();
+ void SetStage(StageT stage);
+ // -- Settings file
+ void SettingsFileRead();
+ void SettingsFileWrite();
+ // -- Tests
+ bool TestQrcRccFiles();
+ bool TestResourcesRead();
+ bool TestResources();
+ void TestInfoFile();
+ // -- Generation
+ void GenerateParentDir();
+ bool GenerateRcc();
+ void GenerateWrapper();
+
+ // -- Utility
+ bool StartProcess(std::string const& workingDirectory,
+ std::vector<std::string> const& command,
+ bool mergedOutput);
+
+private:
// -- Config settings
- std::string ConfigSuffix;
- cmQtAutoGen::MultiConfig MultiConfig;
- // -- Settings
- bool SettingsChanged;
- std::string SettingsFile;
- std::string SettingsString;
+ bool SettingsChanged_;
+ std::string ConfigSuffix_;
+ MultiConfigT MultiConfig_;
// -- Directories
- std::string ProjectSourceDir;
- std::string ProjectBinaryDir;
- std::string CurrentSourceDir;
- std::string CurrentBinaryDir;
- std::string AutogenBuildDir;
- cmFilePathChecksum FilePathChecksum;
+ std::string AutogenBuildDir_;
// -- Qt environment
- std::string RccExecutable;
- std::vector<std::string> RccListOptions;
+ std::string RccExecutable_;
+ std::vector<std::string> RccListOptions_;
// -- Job
- std::string QrcFile;
- std::string RccFile;
- std::vector<std::string> Options;
- std::vector<std::string> Inputs;
+ std::string QrcFile_;
+ std::string QrcFileName_;
+ std::string QrcFileDir_;
+ std::string RccFile_;
+ std::string RccFileWrapper_;
+ std::string RccFileBuild_;
+ std::vector<std::string> Options_;
+ std::vector<std::string> Inputs_;
+ // -- Subprocess
+ ProcessResultT ProcessResult_;
+ std::unique_ptr<ReadOnlyProcessT> Process_;
+ // -- Settings file
+ std::string SettingsFile_;
+ std::string SettingsString_;
+ // -- libuv loop
+ StageT Stage_;
+ bool Error_;
+ bool Generate_;
+ bool BuildFileChanged_;
};
#endif
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
index 6b7143b..4c0a354 100644
--- a/Source/cmServerProtocol.cxx
+++ b/Source/cmServerProtocol.cxx
@@ -1034,8 +1034,8 @@ static Json::Value DumpProjectList(const cmake* cm, std::string const& config)
// Project structure information:
const cmMakefile* mf = lg->GetMakefile();
- pObj[kMINIMUM_CMAKE_VERSION] =
- mf->GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION");
+ auto minVersion = mf->GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION");
+ pObj[kMINIMUM_CMAKE_VERSION] = minVersion ? minVersion : "";
pObj[kSOURCE_DIRECTORY_KEY] = mf->GetCurrentSourceDirectory();
pObj[kBUILD_DIRECTORY_KEY] = mf->GetCurrentBinaryDirectory();
pObj[kTARGETS_KEY] = DumpTargetsList(projectIt.second, config);
diff --git a/Source/cmSourceGroup.cxx b/Source/cmSourceGroup.cxx
index 18bcb49..12ef62b 100644
--- a/Source/cmSourceGroup.cxx
+++ b/Source/cmSourceGroup.cxx
@@ -8,7 +8,7 @@ public:
std::vector<cmSourceGroup> GroupChildren;
};
-cmSourceGroup::cmSourceGroup(const char* name, const char* regex,
+cmSourceGroup::cmSourceGroup(const std::string& name, const char* regex,
const char* parentName)
: Name(name)
{
@@ -70,14 +70,14 @@ std::string const& cmSourceGroup::GetFullName() const
return this->FullName;
}
-bool cmSourceGroup::MatchesRegex(const char* name)
+bool cmSourceGroup::MatchesRegex(const std::string& name)
{
return this->GroupRegex.find(name);
}
-bool cmSourceGroup::MatchesFiles(const char* name)
+bool cmSourceGroup::MatchesFiles(const std::string& name) const
{
- return this->GroupFiles.find(name) != this->GroupFiles.end();
+ return this->GroupFiles.find(name) != this->GroupFiles.cend();
}
void cmSourceGroup::AssignSource(const cmSourceFile* sf)
@@ -95,21 +95,12 @@ void cmSourceGroup::AddChild(cmSourceGroup const& child)
this->Internal->GroupChildren.push_back(child);
}
-cmSourceGroup* cmSourceGroup::LookupChild(const char* name) const
+cmSourceGroup* cmSourceGroup::LookupChild(const std::string& name)
{
- // initializing iterators
- std::vector<cmSourceGroup>::const_iterator iter =
- this->Internal->GroupChildren.begin();
- const std::vector<cmSourceGroup>::const_iterator end =
- this->Internal->GroupChildren.end();
-
- // st
- for (; iter != end; ++iter) {
- std::string const& sgName = iter->GetName();
-
+ for (cmSourceGroup& group : this->Internal->GroupChildren) {
// look if descenened is the one were looking for
- if (sgName == name) {
- return const_cast<cmSourceGroup*>(&(*iter)); // if it so return it
+ if (group.GetName() == name) {
+ return (&group); // if it so return it
}
}
@@ -117,19 +108,13 @@ cmSourceGroup* cmSourceGroup::LookupChild(const char* name) const
return nullptr;
}
-cmSourceGroup* cmSourceGroup::MatchChildrenFiles(const char* name)
+cmSourceGroup* cmSourceGroup::MatchChildrenFiles(const std::string& name)
{
- // initializing iterators
- std::vector<cmSourceGroup>::iterator iter =
- this->Internal->GroupChildren.begin();
- std::vector<cmSourceGroup>::iterator end =
- this->Internal->GroupChildren.end();
-
if (this->MatchesFiles(name)) {
return this;
}
- for (; iter != end; ++iter) {
- cmSourceGroup* result = iter->MatchChildrenFiles(name);
+ for (cmSourceGroup& group : this->Internal->GroupChildren) {
+ cmSourceGroup* result = group.MatchChildrenFiles(name);
if (result) {
return result;
}
@@ -137,16 +122,10 @@ cmSourceGroup* cmSourceGroup::MatchChildrenFiles(const char* name)
return nullptr;
}
-cmSourceGroup* cmSourceGroup::MatchChildrenRegex(const char* name)
+cmSourceGroup* cmSourceGroup::MatchChildrenRegex(const std::string& name)
{
- // initializing iterators
- std::vector<cmSourceGroup>::iterator iter =
- this->Internal->GroupChildren.begin();
- std::vector<cmSourceGroup>::iterator end =
- this->Internal->GroupChildren.end();
-
- for (; iter != end; ++iter) {
- cmSourceGroup* result = iter->MatchChildrenRegex(name);
+ for (cmSourceGroup& group : this->Internal->GroupChildren) {
+ cmSourceGroup* result = group.MatchChildrenRegex(name);
if (result) {
return result;
}
diff --git a/Source/cmSourceGroup.h b/Source/cmSourceGroup.h
index 7c7c35f..b39f8dd 100644
--- a/Source/cmSourceGroup.h
+++ b/Source/cmSourceGroup.h
@@ -26,7 +26,7 @@ class cmSourceGroupInternals;
class cmSourceGroup
{
public:
- cmSourceGroup(const char* name, const char* regex,
+ cmSourceGroup(const std::string& name, const char* regex,
const char* parentName = nullptr);
cmSourceGroup(cmSourceGroup const& r);
~cmSourceGroup();
@@ -50,7 +50,7 @@ public:
/**
* Looks up child and returns it
*/
- cmSourceGroup* LookupChild(const char* name) const;
+ cmSourceGroup* LookupChild(const std::string& name);
/**
* Get the name of this group.
@@ -65,23 +65,23 @@ public:
/**
* Check if the given name matches this group's regex.
*/
- bool MatchesRegex(const char* name);
+ bool MatchesRegex(const std::string& name);
/**
* Check if the given name matches this group's explicit file list.
*/
- bool MatchesFiles(const char* name);
+ bool MatchesFiles(const std::string& name) const;
/**
* Check if the given name matches this group's explicit file list
* in children.
*/
- cmSourceGroup* MatchChildrenFiles(const char* name);
+ cmSourceGroup* MatchChildrenFiles(const std::string& name);
/**
* Check if the given name matches this group's regex in children.
*/
- cmSourceGroup* MatchChildrenRegex(const char* name);
+ cmSourceGroup* MatchChildrenRegex(const std::string& name);
/**
* Assign the given source file to this group. Used only by
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index 5957b5b..00d7e9a 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -107,9 +107,9 @@ bool cmState::LoadCache(const std::string& path, bool internal,
return this->CacheManager->LoadCache(path, internal, excludes, includes);
}
-bool cmState::SaveCache(const std::string& path)
+bool cmState::SaveCache(const std::string& path, cmMessenger* messenger)
{
- return this->CacheManager->SaveCache(path);
+ return this->CacheManager->SaveCache(path, messenger);
}
bool cmState::DeleteCache(const std::string& path)
diff --git a/Source/cmState.h b/Source/cmState.h
index e03ad89..7282f0a 100644
--- a/Source/cmState.h
+++ b/Source/cmState.h
@@ -23,6 +23,7 @@ class cmCacheManager;
class cmCommand;
class cmPropertyDefinition;
class cmStateSnapshot;
+class cmMessenger;
class cmState
{
@@ -59,7 +60,7 @@ public:
std::set<std::string>& excludes,
std::set<std::string>& includes);
- bool SaveCache(const std::string& path);
+ bool SaveCache(const std::string& path, cmMessenger* messenger);
bool DeleteCache(const std::string& path);
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 1974be3..663a4c9 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -247,6 +247,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
this->SetPropertyDefault("AUTOMOC", nullptr);
this->SetPropertyDefault("AUTOUIC", nullptr);
this->SetPropertyDefault("AUTORCC", nullptr);
+ this->SetPropertyDefault("AUTOGEN_PARALLEL", nullptr);
this->SetPropertyDefault("AUTOMOC_COMPILER_PREDEFINES", nullptr);
this->SetPropertyDefault("AUTOMOC_DEPEND_FILTERS", nullptr);
this->SetPropertyDefault("AUTOMOC_MACRO_NAMES", nullptr);
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index ee9db43..1b09600 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -2319,6 +2319,18 @@ void cmVisualStudio10TargetGenerator::OutputLinkIncremental(
}
}
+std::vector<std::string> cmVisualStudio10TargetGenerator::GetIncludes(
+ std::string const& config, std::string const& lang) const
+{
+ std::vector<std::string> includes;
+ this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
+ lang, config);
+ for (std::string& i : includes) {
+ this->ConvertToWindowsSlash(i);
+ }
+ return includes;
+}
+
bool cmVisualStudio10TargetGenerator::ComputeClOptions()
{
for (std::string const& i : this->Configurations) {
@@ -2379,6 +2391,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
}
}
}
+ this->LangForClCompile = langForClCompile;
if (!langForClCompile.empty()) {
std::string baseFlagVar = "CMAKE_";
baseFlagVar += langForClCompile;
@@ -2422,8 +2435,10 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
std::vector<std::string> targetDefines;
switch (this->ProjectType) {
case vcxproj:
- this->GeneratorTarget->GetCompileDefinitions(targetDefines, configName,
- "CXX");
+ if (!langForClCompile.empty()) {
+ this->GeneratorTarget->GetCompileDefinitions(targetDefines, configName,
+ langForClCompile);
+ }
break;
case csproj:
this->GeneratorTarget->GetCompileDefinitions(targetDefines, configName,
@@ -2487,7 +2502,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
}
void cmVisualStudio10TargetGenerator::WriteClOptions(
- std::string const& configName, std::vector<std::string> const& includes)
+ std::string const& configName)
{
Options& clOptions = *(this->ClOptions[configName]);
if (this->ProjectType == csproj) {
@@ -2495,12 +2510,16 @@ void cmVisualStudio10TargetGenerator::WriteClOptions(
}
this->WriteString("<ClCompile>\n", 2);
clOptions.PrependInheritedString("AdditionalOptions");
- clOptions.AppendFlag("AdditionalIncludeDirectories", includes);
+ if (!this->LangForClCompile.empty()) {
+ std::vector<std::string> const includes =
+ this->GetIncludes(configName, this->LangForClCompile);
+ clOptions.AppendFlag("AdditionalIncludeDirectories", includes);
+ }
clOptions.AppendFlag("AdditionalIncludeDirectories",
"%(AdditionalIncludeDirectories)");
clOptions.OutputFlagMap(*this->BuildFileStream, " ");
clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ",
- "\n", "CXX");
+ "\n", this->LangForClCompile);
if (this->NsightTegra) {
if (const char* processMax =
@@ -2581,7 +2600,7 @@ bool cmVisualStudio10TargetGenerator::ComputeRcOptions(
}
void cmVisualStudio10TargetGenerator::WriteRCOptions(
- std::string const& configName, std::vector<std::string> const& includes)
+ std::string const& configName)
{
if (!this->MSTools) {
return;
@@ -2591,6 +2610,8 @@ void cmVisualStudio10TargetGenerator::WriteRCOptions(
Options& rcOptions = *(this->RcOptions[configName]);
rcOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ",
"\n", "RC");
+ std::vector<std::string> const includes =
+ this->GetIncludes(configName, "RC");
rcOptions.AppendFlag("AdditionalIncludeDirectories", includes);
rcOptions.AppendFlag("AdditionalIncludeDirectories",
"%(AdditionalIncludeDirectories)");
@@ -2646,6 +2667,7 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions(
cudaOptions.AddFlag("GPUDebugInfo", "false");
}
+ bool notPtx = true;
if (this->GeneratorTarget->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION")) {
cudaOptions.AddFlag("GenerateRelocatableDeviceCode", "true");
} else if (this->GeneratorTarget->GetPropertyAsBool(
@@ -2654,6 +2676,16 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions(
// We drop the %(Extension) component as CMake expects all PTX files
// to not have the source file extension at all
cudaOptions.AddFlag("CompileOut", "$(IntDir)%(Filename).ptx");
+ notPtx = false;
+ }
+
+ if (notPtx &&
+ cmSystemTools::VersionCompareGreaterEq(
+ "8.0", this->GlobalGenerator->GetPlatformToolsetCudaString())) {
+ // Explicitly state that we want this file to be treated as a
+ // CUDA file no matter what the file extensions is
+ // This is only needed for < CUDA 9
+ cudaOptions.AppendFlagString("AdditionalOptions", "-x cu");
}
// CUDA automatically passes the proper '--machine' flag to nvcc
@@ -2701,7 +2733,7 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions(
}
void cmVisualStudio10TargetGenerator::WriteCudaOptions(
- std::string const& configName, std::vector<std::string> const& includes)
+ std::string const& configName)
{
if (!this->MSTools || !this->GlobalGenerator->IsCudaEnabled()) {
return;
@@ -2709,6 +2741,8 @@ void cmVisualStudio10TargetGenerator::WriteCudaOptions(
this->WriteString("<CudaCompile>\n", 2);
Options& cudaOptions = *(this->CudaOptions[configName]);
+ std::vector<std::string> const includes =
+ this->GetIncludes(configName, "CUDA");
cudaOptions.AppendFlag("Include", includes);
cudaOptions.AppendFlag("Include", "%(Include)");
cudaOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ",
@@ -2823,7 +2857,7 @@ bool cmVisualStudio10TargetGenerator::ComputeMasmOptions(
}
void cmVisualStudio10TargetGenerator::WriteMasmOptions(
- std::string const& configName, std::vector<std::string> const& includes)
+ std::string const& configName)
{
if (!this->MSTools || !this->GlobalGenerator->IsMasmEnabled()) {
return;
@@ -2836,6 +2870,8 @@ void cmVisualStudio10TargetGenerator::WriteMasmOptions(
"\n", "ASM_MASM");
Options& masmOptions = *(this->MasmOptions[configName]);
+ std::vector<std::string> const includes =
+ this->GetIncludes(configName, "ASM_MASM");
masmOptions.AppendFlag("IncludePaths", includes);
masmOptions.AppendFlag("IncludePaths", "%(IncludePaths)");
masmOptions.PrependInheritedString("AdditionalOptions");
@@ -2880,13 +2916,15 @@ bool cmVisualStudio10TargetGenerator::ComputeNasmOptions(
}
void cmVisualStudio10TargetGenerator::WriteNasmOptions(
- std::string const& configName, std::vector<std::string> includes)
+ std::string const& configName)
{
if (!this->GlobalGenerator->IsNasmEnabled()) {
return;
}
this->WriteString("<NASM>\n", 2);
+ std::vector<std::string> includes =
+ this->GetIncludes(configName, "ASM_NASM");
Options& nasmOptions = *(this->NasmOptions[configName]);
for (size_t i = 0; i < includes.size(); i++) {
includes[i] += "\\";
@@ -3434,7 +3472,7 @@ void cmVisualStudio10TargetGenerator::AddTargetsFileAndConfigPair(
}
void cmVisualStudio10TargetGenerator::WriteMidlOptions(
- std::string const& /*config*/, std::vector<std::string> const& includes)
+ std::string const& configName)
{
if (!this->MSTools) {
return;
@@ -3460,6 +3498,8 @@ void cmVisualStudio10TargetGenerator::WriteMidlOptions(
// on the CMake side?
this->WriteString("<Midl>\n", 2);
this->WriteString("<AdditionalIncludeDirectories>", 3);
+ std::vector<std::string> const includes =
+ this->GetIncludes(configName, "MIDL");
for (std::string const& i : includes) {
*this->BuildFileStream << cmVS10EscapeXML(i) << ";";
}
@@ -3484,25 +3524,19 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups()
return;
}
for (std::string const& i : this->Configurations) {
- std::vector<std::string> includes;
- this->LocalGenerator->GetIncludeDirectories(includes,
- this->GeneratorTarget, "C", i);
- for (std::string& ii : includes) {
- this->ConvertToWindowsSlash(ii);
- }
this->WritePlatformConfigTag("ItemDefinitionGroup", i, 1);
*this->BuildFileStream << "\n";
// output cl compile flags <ClCompile></ClCompile>
if (this->GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY) {
- this->WriteClOptions(i, includes);
+ this->WriteClOptions(i);
// output rc compile flags <ResourceCompile></ResourceCompile>
- this->WriteRCOptions(i, includes);
- this->WriteCudaOptions(i, includes);
- this->WriteMasmOptions(i, includes);
- this->WriteNasmOptions(i, includes);
+ this->WriteRCOptions(i);
+ this->WriteCudaOptions(i);
+ this->WriteMasmOptions(i);
+ this->WriteNasmOptions(i);
}
// output midl flags <Midl></Midl>
- this->WriteMidlOptions(i, includes);
+ this->WriteMidlOptions(i);
// write events
if (this->ProjectType != csproj) {
this->WriteEvents(i);
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index fb24f1a..c346164 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -90,18 +90,18 @@ private:
void WriteTargetSpecificReferences();
void WriteTargetsFileReferences();
+ std::vector<std::string> GetIncludes(std::string const& config,
+ std::string const& lang) const;
+
bool ComputeClOptions();
bool ComputeClOptions(std::string const& configName);
- void WriteClOptions(std::string const& config,
- std::vector<std::string> const& includes);
+ void WriteClOptions(std::string const& config);
bool ComputeRcOptions();
bool ComputeRcOptions(std::string const& config);
- void WriteRCOptions(std::string const& config,
- std::vector<std::string> const& includes);
+ void WriteRCOptions(std::string const& config);
bool ComputeCudaOptions();
bool ComputeCudaOptions(std::string const& config);
- void WriteCudaOptions(std::string const& config,
- std::vector<std::string> const& includes);
+ void WriteCudaOptions(std::string const& config);
bool ComputeCudaLinkOptions();
bool ComputeCudaLinkOptions(std::string const& config);
@@ -109,20 +109,17 @@ private:
bool ComputeMasmOptions();
bool ComputeMasmOptions(std::string const& config);
- void WriteMasmOptions(std::string const& config,
- std::vector<std::string> const& includes);
+ void WriteMasmOptions(std::string const& config);
bool ComputeNasmOptions();
bool ComputeNasmOptions(std::string const& config);
- void WriteNasmOptions(std::string const& config,
- std::vector<std::string> includes);
+ void WriteNasmOptions(std::string const& config);
bool ComputeLinkOptions();
bool ComputeLinkOptions(std::string const& config);
bool ComputeLibOptions();
bool ComputeLibOptions(std::string const& config);
void WriteLinkOptions(std::string const& config);
- void WriteMidlOptions(std::string const& config,
- std::vector<std::string> const& includes);
+ void WriteMidlOptions(std::string const& config);
void WriteAntBuildOptions(std::string const& config);
void OutputLinkIncremental(std::string const& configName);
void WriteCustomRule(cmSourceFile const* source,
@@ -180,6 +177,7 @@ private:
OptionsMap MasmOptions;
OptionsMap NasmOptions;
OptionsMap LinkOptions;
+ std::string LangForClCompile;
std::string PathToProjectFile;
std::string ProjectFileExtension;
enum VsProjectType
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 2341dd6..480646e 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -1771,7 +1771,7 @@ bool cmake::LoadCache(const std::string& path, bool internal,
bool cmake::SaveCache(const std::string& path)
{
- bool result = this->State->SaveCache(path);
+ bool result = this->State->SaveCache(path, this->GetMessenger());
static const char* entries[] = { "CMAKE_CACHE_MAJOR_VERSION",
"CMAKE_CACHE_MINOR_VERSION",
"CMAKE_CACHE_PATCH_VERSION",
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index f660f43..2c3bda2 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -103,7 +103,7 @@ void CMakeCommandUsage(const char* program)
<< " sleep <number>... - sleep for given number of seconds\n"
<< " tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...]\n"
<< " - create or extract a tar or zip archive\n"
- << " time command [args...] - run command and return elapsed time\n"
+ << " time command [args...] - run command and display elapsed time\n"
<< " touch file - touch a file.\n"
<< " touch_nocreate file - touch a file but do not create it.\n"
#if defined(_WIN32) && !defined(__CYGWIN__)
diff --git a/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt b/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt
index f96283d..7dc7995 100644
--- a/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt
+++ b/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt
@@ -26,18 +26,18 @@ target_compile_definitions(consumer
PRIVATE
)
-if (CMAKE_GENERATOR MATCHES "Makefiles" OR CMAKE_GENERATOR MATCHES "Ninja")
- target_sources(consumer PRIVATE
- "${CMAKE_CURRENT_SOURCE_DIR}/consumer.c"
- )
- target_compile_definitions(consumer
- PRIVATE
- CONSUMER_LANG_$<COMPILE_LANGUAGE>
- LANG_IS_CXX=$<COMPILE_LANGUAGE:CXX>
- LANG_IS_C=$<COMPILE_LANGUAGE:C>
- )
+target_sources(consumer PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/consumer.c"
+)
+target_compile_definitions(consumer
+ PRIVATE
+ CONSUMER_LANG_$<COMPILE_LANGUAGE>
+ LANG_IS_CXX=$<COMPILE_LANGUAGE:CXX>
+ LANG_IS_C=$<COMPILE_LANGUAGE:C>
+)
+if(CMAKE_GENERATOR MATCHES "Visual Studio|Xcode")
target_compile_definitions(consumer
- PRIVATE -DTEST_LANG_DEFINES
+ PRIVATE TEST_LANG_DEFINES_FOR_VISUAL_STUDIO_OR_XCODE
)
endif()
diff --git a/Tests/CMakeCommands/target_compile_definitions/consumer.c b/Tests/CMakeCommands/target_compile_definitions/consumer.c
index 7931a6f..e134a8b 100644
--- a/Tests/CMakeCommands/target_compile_definitions/consumer.c
+++ b/Tests/CMakeCommands/target_compile_definitions/consumer.c
@@ -1,5 +1,23 @@
-#ifdef TEST_LANG_DEFINES
+// Visual Studio allows only one set of flags for C and C++.
+// In a target using C++ we pick the C++ flags even for C sources.
+#ifdef TEST_LANG_DEFINES_FOR_VISUAL_STUDIO_OR_XCODE
+#ifndef CONSUMER_LANG_CXX
+#error Expected CONSUMER_LANG_CXX
+#endif
+
+#ifdef CONSUMER_LANG_C
+#error Unexpected CONSUMER_LANG_C
+#endif
+
+#if !LANG_IS_CXX
+#error Expected LANG_IS_CXX
+#endif
+
+#if LANG_IS_C
+#error Unexpected LANG_IS_C
+#endif
+#else
#ifdef CONSUMER_LANG_CXX
#error Unexpected CONSUMER_LANG_CXX
#endif
diff --git a/Tests/CMakeCommands/target_compile_definitions/consumer.cpp b/Tests/CMakeCommands/target_compile_definitions/consumer.cpp
index 0202c17..69ea151 100644
--- a/Tests/CMakeCommands/target_compile_definitions/consumer.cpp
+++ b/Tests/CMakeCommands/target_compile_definitions/consumer.cpp
@@ -15,7 +15,6 @@
#error Expected DASH_D_DEFINE
#endif
-#ifdef TEST_LANG_DEFINES
#ifndef CONSUMER_LANG_CXX
#error Expected CONSUMER_LANG_CXX
#endif
@@ -31,7 +30,6 @@
#if LANG_IS_C
#error Unexpected LANG_IS_C
#endif
-#endif
int main()
{
diff --git a/Tests/CMakeCommands/target_include_directories/CMakeLists.txt b/Tests/CMakeCommands/target_include_directories/CMakeLists.txt
index d57556a..8713d99 100644
--- a/Tests/CMakeCommands/target_include_directories/CMakeLists.txt
+++ b/Tests/CMakeCommands/target_include_directories/CMakeLists.txt
@@ -42,17 +42,17 @@ add_executable(consumer
"${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp"
)
-if (CMAKE_GENERATOR MATCHES "Makefiles" OR CMAKE_GENERATOR MATCHES "Ninja")
- target_sources(consumer PRIVATE
- "${CMAKE_CURRENT_SOURCE_DIR}/consumer.c"
- )
- target_include_directories(consumer
- PRIVATE
- $<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/cxx_only>
- $<$<COMPILE_LANGUAGE:C>:${CMAKE_CURRENT_SOURCE_DIR}/c_only>
- )
+target_sources(consumer PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/consumer.c"
+)
+target_include_directories(consumer
+ PRIVATE
+ $<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/cxx_only>
+ $<$<COMPILE_LANGUAGE:C>:${CMAKE_CURRENT_SOURCE_DIR}/c_only>
+)
+if(CMAKE_GENERATOR MATCHES "Visual Studio|Xcode")
target_compile_definitions(consumer
- PRIVATE -DTEST_LANG_DEFINES
+ PRIVATE TEST_LANG_DEFINES_FOR_VISUAL_STUDIO_OR_XCODE
)
endif()
diff --git a/Tests/CMakeCommands/target_include_directories/consumer.c b/Tests/CMakeCommands/target_include_directories/consumer.c
index ae88f92..419c2d2 100644
--- a/Tests/CMakeCommands/target_include_directories/consumer.c
+++ b/Tests/CMakeCommands/target_include_directories/consumer.c
@@ -1,5 +1,13 @@
-#ifdef TEST_LANG_DEFINES
+// Visual Studio allows only one set of flags for C and C++.
+// In a target using C++ we pick the C++ flags even for C sources.
+#ifdef TEST_LANG_DEFINES_FOR_VISUAL_STUDIO_OR_XCODE
+#include "cxx_only.h"
+
+#ifndef CXX_ONLY_DEFINE
+#error Expected CXX_ONLY_DEFINE
+#endif
+#else
#include "c_only.h"
#ifndef C_ONLY_DEFINE
diff --git a/Tests/CMakeCommands/target_include_directories/consumer.cpp b/Tests/CMakeCommands/target_include_directories/consumer.cpp
index 0f8153b..1e018ad 100644
--- a/Tests/CMakeCommands/target_include_directories/consumer.cpp
+++ b/Tests/CMakeCommands/target_include_directories/consumer.cpp
@@ -1,12 +1,10 @@
#include "consumer.h"
#include "common.h"
+#include "cxx_only.h"
#include "interfaceinclude.h"
#include "publicinclude.h"
#include "relative_dir.h"
-#ifdef TEST_LANG_DEFINES
-#include "cxx_only.h"
-#endif
#ifdef PRIVATEINCLUDE_DEFINE
#error Unexpected PRIVATEINCLUDE_DEFINE
@@ -32,11 +30,9 @@
#error Expected CONSUMER_DEFINE
#endif
-#ifdef TEST_LANG_DEFINES
#ifndef CXX_ONLY_DEFINE
#error Expected CXX_ONLY_DEFINE
#endif
-#endif
int main()
{
diff --git a/Tests/CudaOnly/WithDefs/CMakeLists.txt b/Tests/CudaOnly/WithDefs/CMakeLists.txt
index 5bd93a4..926d9ed 100644
--- a/Tests/CudaOnly/WithDefs/CMakeLists.txt
+++ b/Tests/CudaOnly/WithDefs/CMakeLists.txt
@@ -21,19 +21,13 @@ set(release_compile_defs DEFREL)
#this verifies we can pass things such as '_','(' to nvcc
add_definitions("-DPACKED_DEFINE=__attribute__((packed))")
-if(CMAKE_GENERATOR MATCHES "Visual Studio")
- # CUDA MSBuild rules do not pass '-x cu' to nvcc
- set(main main_for_vs.cu)
-else()
- set(main main.notcu)
- set_source_files_properties(main.notcu PROPERTIES LANGUAGE CUDA)
-endif()
-add_executable(CudaOnlyWithDefs ${main})
+add_executable(CudaOnlyWithDefs main.notcu)
+set_source_files_properties(main.notcu PROPERTIES LANGUAGE CUDA)
target_compile_options(CudaOnlyWithDefs
PRIVATE
- -DCOMPILE_LANG_$<COMPILE_LANGUAGE>
- -DLANG_IS_CUDA=$<COMPILE_LANGUAGE:CUDA>
+ -DFLAG_COMPILE_LANG_$<COMPILE_LANGUAGE>
+ -DFLAG_LANG_IS_CUDA=$<COMPILE_LANGUAGE:CUDA>
-Xcompiler=-DHOST_DEFINE
$<$<CONFIG:DEBUG>:$<BUILD_INTERFACE:${debug_compile_flags}>>
)
@@ -41,8 +35,15 @@ target_compile_options(CudaOnlyWithDefs
target_compile_definitions(CudaOnlyWithDefs
PRIVATE
$<$<CONFIG:RELEASE>:$<BUILD_INTERFACE:${release_compile_defs}>>
+ -DDEF_COMPILE_LANG_$<COMPILE_LANGUAGE>
+ -DDEF_LANG_IS_CUDA=$<COMPILE_LANGUAGE:CUDA>
)
+target_include_directories(CudaOnlyWithDefs
+ PRIVATE
+ $<$<COMPILE_LANGUAGE:CUDA>:${CMAKE_CURRENT_SOURCE_DIR}/inc_cuda>
+)
+
if(APPLE)
# Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
set_property(TARGET CudaOnlyWithDefs PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
diff --git a/Tests/CudaOnly/WithDefs/inc_cuda/inc_cuda.h b/Tests/CudaOnly/WithDefs/inc_cuda/inc_cuda.h
new file mode 100644
index 0000000..e228b58
--- /dev/null
+++ b/Tests/CudaOnly/WithDefs/inc_cuda/inc_cuda.h
@@ -0,0 +1 @@
+#define INC_CUDA
diff --git a/Tests/CudaOnly/WithDefs/main.notcu b/Tests/CudaOnly/WithDefs/main.notcu
index bfb3577..3793d74 100644
--- a/Tests/CudaOnly/WithDefs/main.notcu
+++ b/Tests/CudaOnly/WithDefs/main.notcu
@@ -2,6 +2,11 @@
#include <cuda_runtime.h>
#include <iostream>
+#include <inc_cuda.h>
+#ifndef INC_CUDA
+#error "INC_CUDA not defined!"
+#endif
+
#ifndef HOST_DEFINE
#error "HOST_DEFINE not defined!"
#endif
@@ -10,16 +15,28 @@
#error "PACKED_DEFINE not defined!"
#endif
-#ifndef COMPILE_LANG_CUDA
-#error "COMPILE_LANG_CUDA not defined!"
+#ifndef FLAG_COMPILE_LANG_CUDA
+#error "FLAG_COMPILE_LANG_CUDA not defined!"
+#endif
+
+#ifndef FLAG_LANG_IS_CUDA
+#error "FLAG_LANG_IS_CUDA not defined!"
+#endif
+
+#if !FLAG_LANG_IS_CUDA
+#error "Expected FLAG_LANG_IS_CUDA"
+#endif
+
+#ifndef DEF_COMPILE_LANG_CUDA
+#error "DEF_COMPILE_LANG_CUDA not defined!"
#endif
-#ifndef LANG_IS_CUDA
-#error "LANG_IS_CUDA not defined!"
+#ifndef DEF_LANG_IS_CUDA
+#error "DEF_LANG_IS_CUDA not defined!"
#endif
-#if !LANG_IS_CUDA
-#error "Expected LANG_IS_CUDA"
+#if !DEF_LANG_IS_CUDA
+#error "Expected DEF_LANG_IS_CUDA"
#endif
static __global__ void DetermineIfValidCudaDevice()
diff --git a/Tests/CudaOnly/WithDefs/main_for_vs.cu b/Tests/CudaOnly/WithDefs/main_for_vs.cu
deleted file mode 100644
index 56078e7..0000000
--- a/Tests/CudaOnly/WithDefs/main_for_vs.cu
+++ /dev/null
@@ -1 +0,0 @@
-#include "main.notcu"
diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt
index 0585d0c..4586357 100644
--- a/Tests/GeneratorExpression/CMakeLists.txt
+++ b/Tests/GeneratorExpression/CMakeLists.txt
@@ -269,10 +269,8 @@ set_property(SOURCE srcgenex_flags_COMPILE_LANGUAGE.c PROPERTY COMPILE_FLAGS "$<
add_executable(srcgenex_defs srcgenex_defs.c)
set_property(SOURCE srcgenex_defs.c PROPERTY COMPILE_DEFINITIONS NAME=$<TARGET_PROPERTY:NAME>)
-if (CMAKE_GENERATOR MATCHES "Makefiles|Ninja|Watcom WMake")
- add_executable(srcgenex_defs_COMPILE_LANGUAGE srcgenex_defs_COMPILE_LANGUAGE.c)
- set_property(SOURCE srcgenex_defs_COMPILE_LANGUAGE.c PROPERTY COMPILE_DEFINITIONS $<$<COMPILE_LANGUAGE:C>:NAME=$<TARGET_PROPERTY:NAME>>)
-endif()
+add_executable(srcgenex_defs_COMPILE_LANGUAGE srcgenex_defs_COMPILE_LANGUAGE.c)
+set_property(SOURCE srcgenex_defs_COMPILE_LANGUAGE.c PROPERTY COMPILE_DEFINITIONS $<$<COMPILE_LANGUAGE:C>:NAME=$<TARGET_PROPERTY:NAME>>)
#-----------------------------------------------------------------------------
# Cover test properties with generator expressions.
diff --git a/Tests/QtAutogen/CommonTests.cmake b/Tests/QtAutogen/CommonTests.cmake
index c56780e..2c2e6d6 100644
--- a/Tests/QtAutogen/CommonTests.cmake
+++ b/Tests/QtAutogen/CommonTests.cmake
@@ -29,6 +29,12 @@ ADD_AUTOGEN_TEST(ObjectLibrary someProgram)
if(APPLE AND (NOT QT_TEST_VERSION STREQUAL 4))
ADD_AUTOGEN_TEST(MacOsFW)
endif()
+ADD_AUTOGEN_TEST(Parallel parallel)
+ADD_AUTOGEN_TEST(Parallel1 parallel1)
+ADD_AUTOGEN_TEST(Parallel2 parallel2)
+ADD_AUTOGEN_TEST(Parallel3 parallel3)
+ADD_AUTOGEN_TEST(Parallel4 parallel4)
+ADD_AUTOGEN_TEST(ParallelAUTO parallelAUTO)
ADD_AUTOGEN_TEST(SameName sameName)
ADD_AUTOGEN_TEST(StaticLibraryCycle slc)
ADD_AUTOGEN_TEST(Complex QtAutogen)
diff --git a/Tests/QtAutogen/MocInclude/EObjAExtra_p.hpp b/Tests/QtAutogen/MocInclude/EObjAExtra_p.hpp
index dea6cb5..d8bf284 100644
--- a/Tests/QtAutogen/MocInclude/EObjAExtra_p.hpp
+++ b/Tests/QtAutogen/MocInclude/EObjAExtra_p.hpp
@@ -1,6 +1,8 @@
#ifndef EOBJAEXTRA_P_HPP
#define EOBJAEXTRA_P_HPP
+#include <QObject>
+
class EObjAExtraPrivate : public QObject
{
Q_OBJECT
diff --git a/Tests/QtAutogen/MocInclude/EObjA_p.hpp b/Tests/QtAutogen/MocInclude/EObjA_p.hpp
index 1e0d7e1..9ef5624 100644
--- a/Tests/QtAutogen/MocInclude/EObjA_p.hpp
+++ b/Tests/QtAutogen/MocInclude/EObjA_p.hpp
@@ -1,6 +1,8 @@
#ifndef EOBJA_P_HPP
#define EOBJA_P_HPP
+#include <QObject>
+
class EObjAPrivate : public QObject
{
Q_OBJECT
diff --git a/Tests/QtAutogen/MocInclude/EObjB_p.hpp b/Tests/QtAutogen/MocInclude/EObjB_p.hpp
index 2905f28..84b1ea2 100644
--- a/Tests/QtAutogen/MocInclude/EObjB_p.hpp
+++ b/Tests/QtAutogen/MocInclude/EObjB_p.hpp
@@ -1,6 +1,8 @@
#ifndef EOBJB_P_HPP
#define EOBJB_P_HPP
+#include <QObject>
+
class EObjBPrivate : public QObject
{
Q_OBJECT
diff --git a/Tests/QtAutogen/MocInclude/LObjA_p.h b/Tests/QtAutogen/MocInclude/LObjA_p.h
index ebe8395..97113d6 100644
--- a/Tests/QtAutogen/MocInclude/LObjA_p.h
+++ b/Tests/QtAutogen/MocInclude/LObjA_p.h
@@ -1,6 +1,8 @@
#ifndef LOBJA_P_HPP
#define LOBJA_P_HPP
+#include <QObject>
+
class LObjAPrivate : public QObject
{
Q_OBJECT
diff --git a/Tests/QtAutogen/MocInclude/LObjB_p.h b/Tests/QtAutogen/MocInclude/LObjB_p.h
index b871f2d..b88f40e 100644
--- a/Tests/QtAutogen/MocInclude/LObjB_p.h
+++ b/Tests/QtAutogen/MocInclude/LObjB_p.h
@@ -1,6 +1,8 @@
#ifndef LOBJB_P_HPP
#define LOBJB_P_HPP
+#include <QObject>
+
class LObjBPrivate : public QObject
{
Q_OBJECT
diff --git a/Tests/QtAutogen/MocInclude/ObjA_p.h b/Tests/QtAutogen/MocInclude/ObjA_p.h
index eb60c98..d944bc6 100644
--- a/Tests/QtAutogen/MocInclude/ObjA_p.h
+++ b/Tests/QtAutogen/MocInclude/ObjA_p.h
@@ -1,6 +1,8 @@
#ifndef OBJA_P_HPP
#define OBJA_P_HPP
+#include <QObject>
+
class ObjAPrivate : public QObject
{
Q_OBJECT
diff --git a/Tests/QtAutogen/MocInclude/ObjB_p.h b/Tests/QtAutogen/MocInclude/ObjB_p.h
index 418da65..61ba604 100644
--- a/Tests/QtAutogen/MocInclude/ObjB_p.h
+++ b/Tests/QtAutogen/MocInclude/ObjB_p.h
@@ -1,6 +1,8 @@
#ifndef OBJB_P_HPP
#define OBJB_P_HPP
+#include <QObject>
+
class ObjBPrivate : public QObject
{
Q_OBJECT
diff --git a/Tests/QtAutogen/MocInclude/subExtra/EObjBExtra_p.hpp b/Tests/QtAutogen/MocInclude/subExtra/EObjBExtra_p.hpp
index db8a096..3231fac 100644
--- a/Tests/QtAutogen/MocInclude/subExtra/EObjBExtra_p.hpp
+++ b/Tests/QtAutogen/MocInclude/subExtra/EObjBExtra_p.hpp
@@ -1,6 +1,8 @@
#ifndef EOBJBEXTRA_P_HPP
#define EOBJBEXTRA_P_HPP
+#include <QObject>
+
class EObjBExtraPrivate : public QObject
{
Q_OBJECT
diff --git a/Tests/QtAutogen/MocInclude/subGlobal/GObj_p.hpp b/Tests/QtAutogen/MocInclude/subGlobal/GObj_p.hpp
index 7b37dfd..4a43755 100644
--- a/Tests/QtAutogen/MocInclude/subGlobal/GObj_p.hpp
+++ b/Tests/QtAutogen/MocInclude/subGlobal/GObj_p.hpp
@@ -1,6 +1,8 @@
#ifndef GOBJ_P_HPP
#define GOBJ_P_HPP
+#include <QObject>
+
namespace subGlobal {
class GObjPrivate : public QObject
diff --git a/Tests/QtAutogen/Parallel/CMakeLists.txt b/Tests/QtAutogen/Parallel/CMakeLists.txt
new file mode 100644
index 0000000..9c64804
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.10)
+project(Parallel)
+include("../AutogenTest.cmake")
+
+# Test different values for AUTOGEN_PARALLEL
+include("../Parallel/parallel.cmake")
+
+add_executable(parallel ${PARALLEL_SRC})
+set_target_properties(parallel PROPERTIES AUTOGEN_PARALLEL "")
+target_link_libraries(parallel ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/Parallel/aaa/bbb/data.qrc b/Tests/QtAutogen/Parallel/aaa/bbb/data.qrc
new file mode 100644
index 0000000..0ea3537
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/aaa/bbb/data.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="aaa/bbb">
+ <file>item.hpp</file>
+ <file>item.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/Parallel/aaa/bbb/item.cpp b/Tests/QtAutogen/Parallel/aaa/bbb/item.cpp
new file mode 100644
index 0000000..850206f
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/aaa/bbb/item.cpp
@@ -0,0 +1,22 @@
+#include "item.hpp"
+
+namespace aaa {
+namespace bbb {
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ MocLocal obj;
+}
+}
+}
+
+#include "aaa/bbb/item.moc"
diff --git a/Tests/QtAutogen/Parallel/aaa/bbb/item.hpp b/Tests/QtAutogen/Parallel/aaa/bbb/item.hpp
new file mode 100644
index 0000000..0855043
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/aaa/bbb/item.hpp
@@ -0,0 +1,18 @@
+#ifndef AAA_BBB_ITEM_HPP
+#define AAA_BBB_ITEM_HPP
+
+#include <QObject>
+
+namespace aaa {
+namespace bbb {
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+}
+}
+
+#endif
diff --git a/Tests/QtAutogen/Parallel/aaa/data.qrc b/Tests/QtAutogen/Parallel/aaa/data.qrc
new file mode 100644
index 0000000..379af60
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/aaa/data.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="aaa/">
+ <file>item.hpp</file>
+ <file>item.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/Parallel/aaa/item.cpp b/Tests/QtAutogen/Parallel/aaa/item.cpp
new file mode 100644
index 0000000..e35d3d1
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/aaa/item.cpp
@@ -0,0 +1,22 @@
+#include "item.hpp"
+// Include ui_view.h only in header
+
+namespace aaa {
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ Ui_ViewAAA ui;
+ MocLocal obj;
+}
+}
+
+#include "aaa/item.moc"
diff --git a/Tests/QtAutogen/Parallel/aaa/item.hpp b/Tests/QtAutogen/Parallel/aaa/item.hpp
new file mode 100644
index 0000000..875f72f
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/aaa/item.hpp
@@ -0,0 +1,18 @@
+#ifndef AAA_ITEM_HPP
+#define AAA_ITEM_HPP
+
+#include <QObject>
+// Include ui_view.h only in header
+#include <aaa/ui_view.h>
+
+namespace aaa {
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+}
+
+#endif
diff --git a/Tests/QtAutogen/Parallel/aaa/view.ui b/Tests/QtAutogen/Parallel/aaa/view.ui
new file mode 100644
index 0000000..0f09980
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/aaa/view.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ViewAAA</class>
+ <widget class="QWidget" name="Base">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/Parallel/bbb/aaa/data.qrc b/Tests/QtAutogen/Parallel/bbb/aaa/data.qrc
new file mode 100644
index 0000000..da98009
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/bbb/aaa/data.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="bbb/aaa/">
+ <file>item.hpp</file>
+ <file>item.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/Parallel/bbb/aaa/item.cpp b/Tests/QtAutogen/Parallel/bbb/aaa/item.cpp
new file mode 100644
index 0000000..7ad01c3
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/bbb/aaa/item.cpp
@@ -0,0 +1,22 @@
+#include "item.hpp"
+
+namespace bbb {
+namespace aaa {
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ MocLocal obj;
+}
+}
+}
+
+#include "bbb/aaa/item.moc"
diff --git a/Tests/QtAutogen/Parallel/bbb/aaa/item.hpp b/Tests/QtAutogen/Parallel/bbb/aaa/item.hpp
new file mode 100644
index 0000000..be07ca8
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/bbb/aaa/item.hpp
@@ -0,0 +1,18 @@
+#ifndef BBB_AAA_ITEM_HPP
+#define BBB_AAA_ITEM_HPP
+
+#include <QObject>
+
+namespace bbb {
+namespace aaa {
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+}
+}
+
+#endif
diff --git a/Tests/QtAutogen/Parallel/bbb/data.qrc b/Tests/QtAutogen/Parallel/bbb/data.qrc
new file mode 100644
index 0000000..5b080f5
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/bbb/data.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="bbb/">
+ <file>item.hpp</file>
+ <file>item.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/Parallel/bbb/item.cpp b/Tests/QtAutogen/Parallel/bbb/item.cpp
new file mode 100644
index 0000000..9ef128e
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/bbb/item.cpp
@@ -0,0 +1,23 @@
+#include "item.hpp"
+// Include ui_view.h only in source
+#include <bbb/ui_view.h>
+
+namespace bbb {
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ Ui_ViewBBB ui;
+ MocLocal obj;
+}
+}
+
+#include "bbb/item.moc"
diff --git a/Tests/QtAutogen/Parallel/bbb/item.hpp b/Tests/QtAutogen/Parallel/bbb/item.hpp
new file mode 100644
index 0000000..d39a9d7
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/bbb/item.hpp
@@ -0,0 +1,17 @@
+#ifndef BBB_ITEM_HPP
+#define BBB_ITEM_HPP
+
+#include <QObject>
+// Include ui_view.h only in source
+
+namespace bbb {
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+}
+
+#endif
diff --git a/Tests/QtAutogen/Parallel/bbb/view.ui b/Tests/QtAutogen/Parallel/bbb/view.ui
new file mode 100644
index 0000000..a8f506e
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/bbb/view.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ViewBBB</class>
+ <widget class="QWidget" name="Base">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/Parallel/ccc/data.qrc b/Tests/QtAutogen/Parallel/ccc/data.qrc
new file mode 100644
index 0000000..f934c39
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/ccc/data.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="ccc/">
+ <file>item.hpp</file>
+ <file>item.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/Parallel/ccc/item.cpp b/Tests/QtAutogen/Parallel/ccc/item.cpp
new file mode 100644
index 0000000..ab8a281
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/ccc/item.cpp
@@ -0,0 +1,25 @@
+#include "item.hpp"
+// Include ui_view.h in source and header
+#include <ccc/ui_view.h>
+
+namespace ccc {
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ Ui_ViewCCC ui;
+ MocLocal obj;
+}
+}
+
+// Include own moc files
+#include "ccc/item.moc"
+#include "moc_item.cpp"
diff --git a/Tests/QtAutogen/Parallel/ccc/item.hpp b/Tests/QtAutogen/Parallel/ccc/item.hpp
new file mode 100644
index 0000000..20d9dd9
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/ccc/item.hpp
@@ -0,0 +1,18 @@
+#ifndef CCC_ITEM_HPP
+#define CCC_ITEM_HPP
+
+#include <QObject>
+// Include ui_view.h in source and header
+#include <ccc/ui_view.h>
+
+namespace ccc {
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+}
+
+#endif
diff --git a/Tests/QtAutogen/Parallel/ccc/view.ui b/Tests/QtAutogen/Parallel/ccc/view.ui
new file mode 100644
index 0000000..7989c69
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/ccc/view.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ViewCCC</class>
+ <widget class="QWidget" name="Base">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/Parallel/data.qrc b/Tests/QtAutogen/Parallel/data.qrc
new file mode 100644
index 0000000..4ce0b4e
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/data.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>main.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/Parallel/item.cpp b/Tests/QtAutogen/Parallel/item.cpp
new file mode 100644
index 0000000..3d1fbe7
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/item.cpp
@@ -0,0 +1,20 @@
+#include "item.hpp"
+// Include ui_view.h in source and header
+#include <ui_view.h>
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ Ui_View ui;
+ MocLocal obj;
+}
+
+#include "item.moc"
diff --git a/Tests/QtAutogen/Parallel/item.hpp b/Tests/QtAutogen/Parallel/item.hpp
new file mode 100644
index 0000000..75e83f4
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/item.hpp
@@ -0,0 +1,15 @@
+#ifndef ITEM_HPP
+#define ITEM_HPP
+
+#include <QObject>
+// Include ui_view.h in source and header
+#include <ui_view.h>
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+
+#endif
diff --git a/Tests/QtAutogen/Parallel/main.cpp b/Tests/QtAutogen/Parallel/main.cpp
new file mode 100644
index 0000000..a4ffcb3
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/main.cpp
@@ -0,0 +1,16 @@
+#include "aaa/bbb/item.hpp"
+#include "aaa/item.hpp"
+#include "bbb/aaa/item.hpp"
+#include "bbb/item.hpp"
+#include "ccc/item.hpp"
+
+int main(int argv, char** args)
+{
+ // Object instances
+ ::aaa::Item aaa_item;
+ ::aaa::bbb::Item aaa_bbb_item;
+ ::bbb::Item bbb_item;
+ ::bbb::aaa::Item bbb_aaa_item;
+ ::ccc::Item ccc_item;
+ return 0;
+}
diff --git a/Tests/QtAutogen/Parallel/parallel.cmake b/Tests/QtAutogen/Parallel/parallel.cmake
new file mode 100644
index 0000000..551bcd8
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/parallel.cmake
@@ -0,0 +1,24 @@
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTOUIC ON)
+set(CMAKE_AUTORCC ON)
+
+
+set(PBASE ${CMAKE_CURRENT_LIST_DIR})
+set(PARALLEL_SRC
+ ${PBASE}/aaa/bbb/item.cpp
+ ${PBASE}/aaa/bbb/data.qrc
+ ${PBASE}/aaa/item.cpp
+ ${PBASE}/aaa/data.qrc
+
+ ${PBASE}/bbb/aaa/item.cpp
+ ${PBASE}/bbb/aaa/data.qrc
+ ${PBASE}/bbb/item.cpp
+ ${PBASE}/bbb/data.qrc
+
+ ${PBASE}/ccc/item.cpp
+ ${PBASE}/ccc/data.qrc
+
+ ${PBASE}/item.cpp
+ ${PBASE}/data.qrc
+ ${PBASE}/main.cpp
+)
diff --git a/Tests/QtAutogen/Parallel/view.ui b/Tests/QtAutogen/Parallel/view.ui
new file mode 100644
index 0000000..2ffe734
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/view.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>View</class>
+ <widget class="QWidget" name="Base">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/Parallel1/CMakeLists.txt b/Tests/QtAutogen/Parallel1/CMakeLists.txt
new file mode 100644
index 0000000..9c0b4e5
--- /dev/null
+++ b/Tests/QtAutogen/Parallel1/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.10)
+project(Parallel1)
+include("../AutogenTest.cmake")
+
+# Test different values for AUTOGEN_PARALLEL
+include("../Parallel/parallel.cmake")
+
+add_executable(parallel1 ${PARALLEL_SRC})
+set_target_properties(parallel1 PROPERTIES AUTOGEN_PARALLEL 1)
+target_link_libraries(parallel1 ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/Parallel2/CMakeLists.txt b/Tests/QtAutogen/Parallel2/CMakeLists.txt
new file mode 100644
index 0000000..74c38f1
--- /dev/null
+++ b/Tests/QtAutogen/Parallel2/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.10)
+project(Parallel2)
+include("../AutogenTest.cmake")
+
+# Test different values for AUTOGEN_PARALLEL
+include("../Parallel/parallel.cmake")
+
+add_executable(parallel2 ${PARALLEL_SRC})
+set_target_properties(parallel2 PROPERTIES AUTOGEN_PARALLEL 2)
+target_link_libraries(parallel2 ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/Parallel3/CMakeLists.txt b/Tests/QtAutogen/Parallel3/CMakeLists.txt
new file mode 100644
index 0000000..c735531
--- /dev/null
+++ b/Tests/QtAutogen/Parallel3/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.10)
+project(Parallel3)
+include("../AutogenTest.cmake")
+
+# Test different values for AUTOGEN_PARALLEL
+include("../Parallel/parallel.cmake")
+
+add_executable(parallel3 ${PARALLEL_SRC})
+set_target_properties(parallel3 PROPERTIES AUTOGEN_PARALLEL 3)
+target_link_libraries(parallel3 ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/Parallel4/CMakeLists.txt b/Tests/QtAutogen/Parallel4/CMakeLists.txt
new file mode 100644
index 0000000..c012ccd
--- /dev/null
+++ b/Tests/QtAutogen/Parallel4/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.10)
+project(Parallel4)
+include("../AutogenTest.cmake")
+
+# Test different values for AUTOGEN_PARALLEL
+include("../Parallel/parallel.cmake")
+
+add_executable(parallel4 ${PARALLEL_SRC})
+set_target_properties(parallel4 PROPERTIES AUTOGEN_PARALLEL 4)
+target_link_libraries(parallel4 ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/ParallelAUTO/CMakeLists.txt b/Tests/QtAutogen/ParallelAUTO/CMakeLists.txt
new file mode 100644
index 0000000..3fd3ebc
--- /dev/null
+++ b/Tests/QtAutogen/ParallelAUTO/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.10)
+project(ParallelAUTO)
+include("../AutogenTest.cmake")
+
+# Test different values for AUTOGEN_PARALLEL
+include("../Parallel/parallel.cmake")
+
+add_executable(parallelAUTO ${PARALLEL_SRC})
+set_target_properties(parallelAUTO PROPERTIES AUTOGEN_PARALLEL "AUTO")
+target_link_libraries(parallelAUTO ${QT_LIBRARIES})
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 8eb8568..e440b7f 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -339,6 +339,7 @@ add_RunCMake_test(CPackInstallProperties)
add_RunCMake_test(ExternalProject)
add_RunCMake_test(FetchContent)
add_RunCMake_test(CTestCommandLine)
+add_RunCMake_test(CacheNewline)
# Only run this test on unix platforms that support
# symbolic links
if(UNIX)
@@ -351,8 +352,6 @@ add_RunCMake_test(IfacePaths_INCLUDE_DIRECTORIES TEST_DIR IfacePaths)
set(IfacePaths_SOURCES_ARGS -DTEST_PROP=SOURCES)
add_RunCMake_test(IfacePaths_SOURCES TEST_DIR IfacePaths)
-add_RunCMake_test(COMPILE_LANGUAGE-genex)
-
# Matlab module related tests
if(CMake_TEST_FindMatlab)
add_RunCMake_test(FindMatlab)
diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-result.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-result.txt
deleted file mode 100644
index d00491f..0000000
--- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-result.txt
+++ /dev/null
@@ -1 +0,0 @@
-1
diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-stderr-VS.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-stderr-VS.txt
deleted file mode 100644
index 42c1485..0000000
--- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-stderr-VS.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-CMake Error at CompileDefinitions.cmake:5 \(target_compile_definitions\):
- Error evaluating generator expression:
-
- \$<COMPILE_LANGUAGE:CXX>
-
- \$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS and
- file\(GENERATE\) with the Visual Studio generator.
-Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-stderr-Xcode.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-stderr-Xcode.txt
deleted file mode 100644
index 7879a79..0000000
--- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-stderr-Xcode.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-CMake Error at CompileDefinitions.cmake:5 \(target_compile_definitions\):
- Error evaluating generator expression:
-
- \$<COMPILE_LANGUAGE:CXX>
-
- \$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS and
- file\(GENERATE\) with the Xcode generator.
-Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions.cmake b/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions.cmake
deleted file mode 100644
index 7935d88..0000000
--- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions.cmake
+++ /dev/null
@@ -1,5 +0,0 @@
-
-enable_language(CXX)
-
-add_executable(main main.cpp)
-target_compile_definitions(main PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-DANYTHING>)
diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-result.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-result.txt
deleted file mode 100644
index d00491f..0000000
--- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-result.txt
+++ /dev/null
@@ -1 +0,0 @@
-1
diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-VS.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-VS.txt
deleted file mode 100644
index 3806ed1..0000000
--- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-VS.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-CMake Error at IncludeDirectories.cmake:5 \(target_include_directories\):
- Error evaluating generator expression:
-
- \$<COMPILE_LANGUAGE:CXX>
-
- \$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS and
- file\(GENERATE\) with the Visual Studio generator.
-Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-Xcode.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-Xcode.txt
deleted file mode 100644
index a3fb9c5..0000000
--- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-Xcode.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-CMake Error at IncludeDirectories.cmake:5 \(target_include_directories\):
- Error evaluating generator expression:
-
- \$<COMPILE_LANGUAGE:CXX>
-
- \$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS and
- file\(GENERATE\) with the Xcode generator.
-Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories.cmake b/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories.cmake
deleted file mode 100644
index 31771f6..0000000
--- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories.cmake
+++ /dev/null
@@ -1,5 +0,0 @@
-
-enable_language(CXX)
-
-add_executable(main main.cpp)
-target_include_directories(main PRIVATE $<$<COMPILE_LANGUAGE:CXX>:anydir>)
diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-result.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-result.txt
deleted file mode 100644
index d00491f..0000000
--- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-result.txt
+++ /dev/null
@@ -1 +0,0 @@
-1
diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-stderr-VS.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-stderr-VS.txt
deleted file mode 100644
index 5d19153..0000000
--- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-stderr-VS.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-CMake Error:
- Error evaluating generator expression:
-
- \$<COMPILE_LANGUAGE:CXX>
-
- \$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS and
- file\(GENERATE\) with the Visual Studio generator.
diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-stderr-Xcode.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-stderr-Xcode.txt
deleted file mode 100644
index 4a4564e..0000000
--- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-stderr-Xcode.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-CMake Error:
- Error evaluating generator expression:
-
- \$<COMPILE_LANGUAGE:CXX>
-
- \$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS and
- file\(GENERATE\) with the Xcode generator.
diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions.cmake b/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions.cmake
deleted file mode 100644
index 3a07d7d..0000000
--- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions.cmake
+++ /dev/null
@@ -1,5 +0,0 @@
-
-enable_language(CXX)
-
-add_executable(main main.cpp)
-set_property(SOURCE main.cpp PROPERTY COMPILE_DEFINITIONS $<$<COMPILE_LANGUAGE:CXX>:ANYTHING>)
diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/RunCMakeTest.cmake b/Tests/RunCMake/COMPILE_LANGUAGE-genex/RunCMakeTest.cmake
deleted file mode 100644
index 1a93dcd..0000000
--- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/RunCMakeTest.cmake
+++ /dev/null
@@ -1,23 +0,0 @@
-include(RunCMake)
-
-if (RunCMake_GENERATOR STREQUAL "Xcode")
- set(RunCMake-stderr-file CompileDefinitions-stderr-Xcode.txt)
- run_cmake(CompileDefinitions)
-elseif (RunCMake_GENERATOR MATCHES "Visual Studio")
- set(RunCMake-stderr-file CompileDefinitions-stderr-VS.txt)
- run_cmake(CompileDefinitions)
-endif()
-if (RunCMake_GENERATOR STREQUAL "Xcode")
- set(RunCMake-stderr-file IncludeDirectories-stderr-Xcode.txt)
- run_cmake(IncludeDirectories)
-elseif (RunCMake_GENERATOR MATCHES "Visual Studio")
- set(RunCMake-stderr-file IncludeDirectories-stderr-VS.txt)
- run_cmake(IncludeDirectories)
-endif()
-if (RunCMake_GENERATOR STREQUAL "Xcode")
- set(RunCMake-stderr-file PerSourceCompileDefinitions-stderr-Xcode.txt)
- run_cmake(PerSourceCompileDefinitions)
-elseif (RunCMake_GENERATOR MATCHES "Visual Studio")
- set(RunCMake-stderr-file PerSourceCompileDefinitions-stderr-VS.txt)
- run_cmake(PerSourceCompileDefinitions)
-endif()
diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/main.cpp b/Tests/RunCMake/COMPILE_LANGUAGE-genex/main.cpp
deleted file mode 100644
index 766b775..0000000
--- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/main.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
-
-int main()
-{
- return 0;
-}
diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CMakeLists.txt b/Tests/RunCMake/CacheNewline/CMakeLists.txt
index ef2163c..93ee9df 100644
--- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CMakeLists.txt
+++ b/Tests/RunCMake/CacheNewline/CMakeLists.txt
@@ -1,3 +1,3 @@
-cmake_minimum_required(VERSION 3.1)
+cmake_minimum_required(VERSION 3.5)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CacheNewline/CacheNewline-check.cmake b/Tests/RunCMake/CacheNewline/CacheNewline-check.cmake
new file mode 100644
index 0000000..6534f63
--- /dev/null
+++ b/Tests/RunCMake/CacheNewline/CacheNewline-check.cmake
@@ -0,0 +1,16 @@
+set(CACHE_EXPECTED_FILE "${RunCMake_TEST_SOURCE_DIR}/cache-regex.txt")
+set(CACHE_ACTUAL_FILE "${RunCMake_BINARY_DIR}/CacheNewline-build/CMakeCache.txt")
+
+file(READ ${CACHE_EXPECTED_FILE} CACHE_EXPECTED)
+string(REGEX REPLACE "\r\n" "\n" CACHE_EXPECTED "${CACHE_EXPECTED}")
+string(REGEX REPLACE "\n+$" "" CACHE_EXPECTED "${CACHE_EXPECTED}")
+file(READ ${CACHE_ACTUAL_FILE} CACHE_ACTUAL)
+string(REGEX REPLACE "\r\n" "\n" CACHE_ACTUAL "${CACHE_ACTUAL}")
+string(REGEX REPLACE "\n+$" "" CACHE_ACTUAL "${CACHE_ACTUAL}")
+
+if(NOT "${CACHE_ACTUAL}" MATCHES "${CACHE_EXPECTED}")
+ set(RunCMake_TEST_FAILED "${CACHE_ACTUAL_FILE} does not match ${CACHE_EXPECTED_FILE}:
+
+CMakeCache.txt contents = [\n${CACHE_ACTUAL}\n]
+Expected = [\n${CACHE_EXPECTED}\n]")
+endif()
diff --git a/Tests/RunCMake/CacheNewline/CacheNewline-stderr.txt b/Tests/RunCMake/CacheNewline/CacheNewline-stderr.txt
new file mode 100644
index 0000000..726c65c
--- /dev/null
+++ b/Tests/RunCMake/CacheNewline/CacheNewline-stderr.txt
@@ -0,0 +1,2 @@
+CMake Warning:
+ Value of NEWLINE_VARIABLE contained a newline; truncating
diff --git a/Tests/RunCMake/CacheNewline/CacheNewline.cmake b/Tests/RunCMake/CacheNewline/CacheNewline.cmake
new file mode 100644
index 0000000..81851db
--- /dev/null
+++ b/Tests/RunCMake/CacheNewline/CacheNewline.cmake
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.5)
+
+project(CacheNewlineTest NONE)
+
+set(NEWLINE_VARIABLE "a\nb" CACHE STRING "Offending entry")
diff --git a/Tests/RunCMake/CacheNewline/RunCMakeTest.cmake b/Tests/RunCMake/CacheNewline/RunCMakeTest.cmake
new file mode 100644
index 0000000..5e3d2d4
--- /dev/null
+++ b/Tests/RunCMake/CacheNewline/RunCMakeTest.cmake
@@ -0,0 +1,3 @@
+include(RunCMake)
+
+run_cmake(CacheNewline)
diff --git a/Tests/RunCMake/CacheNewline/cache-regex.txt b/Tests/RunCMake/CacheNewline/cache-regex.txt
new file mode 100644
index 0000000..b239dbc
--- /dev/null
+++ b/Tests/RunCMake/CacheNewline/cache-regex.txt
@@ -0,0 +1,6 @@
+//Offending entry
+NEWLINE_VARIABLE:STRING=a
+# WARNING: Value of NEWLINE_VARIABLE contained a newline and was
+# truncated\. Original value:
+# a
+# \\nb
diff --git a/Tests/RunCMake/GenerateExportHeader/GEH.cmake b/Tests/RunCMake/GenerateExportHeader/GEH.cmake
index cfca8fe..cf81f36 100644
--- a/Tests/RunCMake/GenerateExportHeader/GEH.cmake
+++ b/Tests/RunCMake/GenerateExportHeader/GEH.cmake
@@ -53,7 +53,16 @@ endif()
add_subdirectory(lib_shared_and_static)
-add_compiler_export_flags()
+if(CMAKE_SYSTEM_NAME MATCHES "AIX" AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
+ AND CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY)
+ # With GNU 7 on AIX, passing -fvisibility=hidden when driving the
+ # linker for a shared library drops the so init/destruct symbols.
+ # Just use the modern approach instead of testing the macro.
+ set(CMAKE_CXX_VISIBILITY_PRESET hidden)
+ set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
+else()
+ add_compiler_export_flags()
+endif()
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR})
diff --git a/Tests/RunCMake/GenerateExportHeader/libshared/CMakeLists.txt b/Tests/RunCMake/GenerateExportHeader/libshared/CMakeLists.txt
index c4a761c..9516a5a 100644
--- a/Tests/RunCMake/GenerateExportHeader/libshared/CMakeLists.txt
+++ b/Tests/RunCMake/GenerateExportHeader/libshared/CMakeLists.txt
@@ -1,7 +1,5 @@
include(GenerateExportHeader)
-add_compiler_export_flags()
-
set(CMAKE_INCLUDE_CURRENT_DIR ON)
add_library(libshared SHARED libshared.cpp)
diff --git a/Tests/RunCMake/GenerateExportHeader/libstatic/CMakeLists.txt b/Tests/RunCMake/GenerateExportHeader/libstatic/CMakeLists.txt
index 0fd136c..56e8335 100644
--- a/Tests/RunCMake/GenerateExportHeader/libstatic/CMakeLists.txt
+++ b/Tests/RunCMake/GenerateExportHeader/libstatic/CMakeLists.txt
@@ -2,8 +2,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
include(GenerateExportHeader)
-add_compiler_export_flags()
-
# Show that the export header has no effect on a static library.
add_library(libstatic STATIC libstatic.cpp)
diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp
index 5408402..892cdcb 100644
--- a/Utilities/IWYU/mapping.imp
+++ b/Utilities/IWYU/mapping.imp
@@ -23,8 +23,11 @@
# HACK: check whether this can be removed with next iwyu release.
{ include: [ "<bits/shared_ptr.h>", private, "<memory>", public ] },
{ include: [ "<bits/std_function.h>", private, "<functional>", public ] },
+ { include: [ "<bits/stdint-intn.h>", private, "<stdint.h>", public ] },
+ { include: [ "<bits/stdint-uintn.h>", private, "<stdint.h>", public ] },
{ include: [ "<bits/time.h>", private, "<time.h>", public ] },
{ include: [ "<bits/types/clock_t.h>", private, "<time.h>", public ] },
+ { include: [ "<bits/types/mbstate_t.h>", private, "<wchar.h>", public ] },
{ include: [ "<bits/types/struct_timespec.h>", private, "<time.h>", public ] },
{ include: [ "<bits/types/struct_timeval.h>", private, "<time.h>", public ] },
{ include: [ "<bits/types/struct_tm.h>", private, "<time.h>", public ] },
diff --git a/Utilities/Scripts/update-libuv.bash b/Utilities/Scripts/update-libuv.bash
index d7a7d1f..6d423a7 100755
--- a/Utilities/Scripts/update-libuv.bash
+++ b/Utilities/Scripts/update-libuv.bash
@@ -20,6 +20,8 @@ extract_source () {
git_archive
pushd "${extractdir}/${name}-reduced"
echo "* -whitespace" > .gitattributes
+ echo >> src/unix/aix-common.c
+ echo >> src/unix/ibmi.c
popd
}
diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt
index 4c8e228..ba1638e 100644
--- a/Utilities/cmlibuv/CMakeLists.txt
+++ b/Utilities/cmlibuv/CMakeLists.txt
@@ -26,6 +26,7 @@ set(uv_sources
src/threadpool.c
src/uv-common.c
src/uv-common.h
+ src/uv-data-getter-setters.c
src/version.c
)
if(WIN32)
@@ -130,6 +131,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
)
list(APPEND uv_sources
src/unix/aix.c
+ src/unix/aix-common.c
)
endif()
@@ -170,7 +172,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
src/unix/fsevents.c
src/unix/kqueue.c
src/unix/proctitle.c
- src/unix/pthread-barrier.c
)
endif()
diff --git a/Utilities/cmlibuv/LICENSE b/Utilities/cmlibuv/LICENSE
index 41ba44c..28f1733 100644
--- a/Utilities/cmlibuv/LICENSE
+++ b/Utilities/cmlibuv/LICENSE
@@ -62,8 +62,8 @@ The externally maintained libraries used by libuv are:
- stdint-msvc2008.h (from msinttypes), copyright Alexander Chemeris. Three
clause BSD license.
- - pthread-fixes.h, pthread-fixes.c, copyright Google Inc. and Sony Mobile
- Communications AB. Three clause BSD license.
+ - pthread-fixes.c, copyright Google Inc. and Sony Mobile Communications AB.
+ Three clause BSD license.
- android-ifaddrs.h, android-ifaddrs.c, copyright Berkeley Software Design
Inc, Kenneth MacKay and Emergya (Cloud4all, FP7/2007-2013, grant agreement
diff --git a/Utilities/cmlibuv/include/pthread-barrier.h b/Utilities/cmlibuv/include/pthread-barrier.h
index 900ebed..07db9b8a 100644
--- a/Utilities/cmlibuv/include/pthread-barrier.h
+++ b/Utilities/cmlibuv/include/pthread-barrier.h
@@ -23,6 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#endif
#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345
+#define UV__PTHREAD_BARRIER_FALLBACK 1
/*
* To maintain ABI compatibility with
diff --git a/Utilities/cmlibuv/include/uv-errno.h b/Utilities/cmlibuv/include/uv-errno.h
index f137151..8a41533 100644
--- a/Utilities/cmlibuv/include/uv-errno.h
+++ b/Utilities/cmlibuv/include/uv-errno.h
@@ -416,4 +416,16 @@
# define UV__EHOSTDOWN (-4031)
#endif
+#if defined(EREMOTEIO) && !defined(_WIN32)
+# define UV__EREMOTEIO (-EREMOTEIO)
+#else
+# define UV__EREMOTEIO (-4030)
+#endif
+
+#if defined(ENOTTY) && !defined(_WIN32)
+# define UV__ENOTTY (-ENOTTY)
+#else
+# define UV__ENOTTY (-4029)
+#endif
+
#endif /* UV_ERRNO_H_ */
diff --git a/Utilities/cmlibuv/include/uv-os390.h b/Utilities/cmlibuv/include/uv-os390.h
index 58f9261..39e7384 100644
--- a/Utilities/cmlibuv/include/uv-os390.h
+++ b/Utilities/cmlibuv/include/uv-os390.h
@@ -27,4 +27,7 @@
#define UV_PLATFORM_LOOP_FIELDS \
void* ep; \
+#define UV_PLATFORM_FS_EVENT_FIELDS \
+ char rfis_rftok[8]; \
+
#endif /* UV_MVS_H */
diff --git a/Utilities/cmlibuv/include/uv-unix.h b/Utilities/cmlibuv/include/uv-unix.h
index ff59bcb..d8d031f 100644
--- a/Utilities/cmlibuv/include/uv-unix.h
+++ b/Utilities/cmlibuv/include/uv-unix.h
@@ -50,6 +50,8 @@
# include "uv-linux.h"
#elif defined (__MVS__)
# include "uv-os390.h"
+#elif defined(_PASE)
+# include "uv-posix.h"
#elif defined(_AIX)
# include "uv-aix.h"
#elif defined(__sun)
@@ -125,6 +127,7 @@ typedef struct uv_buf_t {
typedef int uv_file;
typedef int uv_os_sock_t;
typedef int uv_os_fd_t;
+typedef pid_t uv_pid_t;
#ifdef CMAKE_BOOTSTRAP
#define UV_ONCE_INIT 0
@@ -379,4 +382,97 @@ typedef struct {
uv_fs_event_cb cb; \
UV_PLATFORM_FS_EVENT_FIELDS \
+/* fs open() flags supported on this platform: */
+#if defined(O_APPEND)
+# define UV_FS_O_APPEND O_APPEND
+#else
+# define UV_FS_O_APPEND 0
+#endif
+#if defined(O_CREAT)
+# define UV_FS_O_CREAT O_CREAT
+#else
+# define UV_FS_O_CREAT 0
+#endif
+#if defined(O_DIRECT)
+# define UV_FS_O_DIRECT O_DIRECT
+#else
+# define UV_FS_O_DIRECT 0
+#endif
+#if defined(O_DIRECTORY)
+# define UV_FS_O_DIRECTORY O_DIRECTORY
+#else
+# define UV_FS_O_DIRECTORY 0
+#endif
+#if defined(O_DSYNC)
+# define UV_FS_O_DSYNC O_DSYNC
+#else
+# define UV_FS_O_DSYNC 0
+#endif
+#if defined(O_EXCL)
+# define UV_FS_O_EXCL O_EXCL
+#else
+# define UV_FS_O_EXCL 0
+#endif
+#if defined(O_EXLOCK)
+# define UV_FS_O_EXLOCK O_EXLOCK
+#else
+# define UV_FS_O_EXLOCK 0
+#endif
+#if defined(O_NOATIME)
+# define UV_FS_O_NOATIME O_NOATIME
+#else
+# define UV_FS_O_NOATIME 0
+#endif
+#if defined(O_NOCTTY)
+# define UV_FS_O_NOCTTY O_NOCTTY
+#else
+# define UV_FS_O_NOCTTY 0
+#endif
+#if defined(O_NOFOLLOW)
+# define UV_FS_O_NOFOLLOW O_NOFOLLOW
+#else
+# define UV_FS_O_NOFOLLOW 0
+#endif
+#if defined(O_NONBLOCK)
+# define UV_FS_O_NONBLOCK O_NONBLOCK
+#else
+# define UV_FS_O_NONBLOCK 0
+#endif
+#if defined(O_RDONLY)
+# define UV_FS_O_RDONLY O_RDONLY
+#else
+# define UV_FS_O_RDONLY 0
+#endif
+#if defined(O_RDWR)
+# define UV_FS_O_RDWR O_RDWR
+#else
+# define UV_FS_O_RDWR 0
+#endif
+#if defined(O_SYMLINK)
+# define UV_FS_O_SYMLINK O_SYMLINK
+#else
+# define UV_FS_O_SYMLINK 0
+#endif
+#if defined(O_SYNC)
+# define UV_FS_O_SYNC O_SYNC
+#else
+# define UV_FS_O_SYNC 0
+#endif
+#if defined(O_TRUNC)
+# define UV_FS_O_TRUNC O_TRUNC
+#else
+# define UV_FS_O_TRUNC 0
+#endif
+#if defined(O_WRONLY)
+# define UV_FS_O_WRONLY O_WRONLY
+#else
+# define UV_FS_O_WRONLY 0
+#endif
+
+/* fs open() flags supported on other platforms: */
+#define UV_FS_O_RANDOM 0
+#define UV_FS_O_SHORT_LIVED 0
+#define UV_FS_O_SEQUENTIAL 0
+#define UV_FS_O_TEMPORARY 0
+
#endif /* UV_UNIX_H */
diff --git a/Utilities/cmlibuv/include/uv-version.h b/Utilities/cmlibuv/include/uv-version.h
index e165809..1dc63e5 100644
--- a/Utilities/cmlibuv/include/uv-version.h
+++ b/Utilities/cmlibuv/include/uv-version.h
@@ -31,7 +31,7 @@
*/
#define UV_VERSION_MAJOR 1
-#define UV_VERSION_MINOR 11
+#define UV_VERSION_MINOR 19
#define UV_VERSION_PATCH 1
#define UV_VERSION_IS_RELEASE 0
#define UV_VERSION_SUFFIX "dev"
diff --git a/Utilities/cmlibuv/include/uv-win.h b/Utilities/cmlibuv/include/uv-win.h
index d3e32a5..6486aab 100644
--- a/Utilities/cmlibuv/include/uv-win.h
+++ b/Utilities/cmlibuv/include/uv-win.h
@@ -20,7 +20,7 @@
*/
#ifndef _WIN32_WINNT
-# define _WIN32_WINNT 0x0502
+# define _WIN32_WINNT 0x0600
#endif
#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
@@ -233,6 +233,7 @@ typedef struct uv_buf_t {
typedef int uv_file;
typedef SOCKET uv_os_sock_t;
typedef HANDLE uv_os_fd_t;
+typedef int uv_pid_t;
typedef HANDLE uv_thread_t;
@@ -659,3 +660,28 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
#ifndef X_OK
#define X_OK 1
#endif
+
+/* fs open() flags supported on this platform: */
+#define UV_FS_O_APPEND _O_APPEND
+#define UV_FS_O_CREAT _O_CREAT
+#define UV_FS_O_EXCL _O_EXCL
+#define UV_FS_O_RANDOM _O_RANDOM
+#define UV_FS_O_RDONLY _O_RDONLY
+#define UV_FS_O_RDWR _O_RDWR
+#define UV_FS_O_SEQUENTIAL _O_SEQUENTIAL
+#define UV_FS_O_SHORT_LIVED _O_SHORT_LIVED
+#define UV_FS_O_TEMPORARY _O_TEMPORARY
+#define UV_FS_O_TRUNC _O_TRUNC
+#define UV_FS_O_WRONLY _O_WRONLY
+
+/* fs open() flags supported on other platforms (or mapped on this platform): */
+#define UV_FS_O_DIRECT 0x02000000 /* FILE_FLAG_NO_BUFFERING */
+#define UV_FS_O_DIRECTORY 0
+#define UV_FS_O_DSYNC 0x04000000 /* FILE_FLAG_WRITE_THROUGH */
+#define UV_FS_O_EXLOCK 0x10000000 /* EXCLUSIVE SHARING MODE */
+#define UV_FS_O_NOATIME 0
+#define UV_FS_O_NOCTTY 0
+#define UV_FS_O_NOFOLLOW 0
+#define UV_FS_O_NONBLOCK 0
+#define UV_FS_O_SYMLINK 0
+#define UV_FS_O_SYNC 0x08000000 /* FILE_FLAG_WRITE_THROUGH */
diff --git a/Utilities/cmlibuv/include/uv.h b/Utilities/cmlibuv/include/uv.h
index 38f5676..328ce9e 100644
--- a/Utilities/cmlibuv/include/uv.h
+++ b/Utilities/cmlibuv/include/uv.h
@@ -144,6 +144,8 @@ extern "C" {
XX(ENXIO, "no such device or address") \
XX(EMLINK, "too many links") \
XX(EHOSTDOWN, "host is down") \
+ XX(EREMOTEIO, "remote I/O error") \
+ XX(ENOTTY, "inappropriate ioctl for device") \
#define UV_HANDLE_TYPE_MAP(XX) \
XX(ASYNC, async) \
@@ -427,7 +429,17 @@ struct uv_handle_s {
};
UV_EXTERN size_t uv_handle_size(uv_handle_type type);
+UV_EXTERN uv_handle_type uv_handle_get_type(const uv_handle_t* handle);
+UV_EXTERN const char* uv_handle_type_name(uv_handle_type type);
+UV_EXTERN void* uv_handle_get_data(const uv_handle_t* handle);
+UV_EXTERN uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle);
+UV_EXTERN void uv_handle_set_data(uv_handle_t* handle, void* data);
+
UV_EXTERN size_t uv_req_size(uv_req_type type);
+UV_EXTERN void* uv_req_get_data(const uv_req_t* req);
+UV_EXTERN void uv_req_set_data(uv_req_t* req, void* data);
+UV_EXTERN uv_req_type uv_req_get_type(const uv_req_t* req);
+UV_EXTERN const char* uv_req_type_name(uv_req_type type);
UV_EXTERN int uv_is_active(const uv_handle_t* handle);
@@ -467,6 +479,8 @@ struct uv_stream_s {
UV_STREAM_FIELDS
};
+UV_EXTERN size_t uv_stream_get_write_queue_size(const uv_stream_t* stream);
+
UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
UV_EXTERN int uv_accept(uv_stream_t* server, uv_stream_t* client);
@@ -644,6 +658,8 @@ UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle,
uv_alloc_cb alloc_cb,
uv_udp_recv_cb recv_cb);
UV_EXTERN int uv_udp_recv_stop(uv_udp_t* handle);
+UV_EXTERN size_t uv_udp_get_send_queue_size(const uv_udp_t* handle);
+UV_EXTERN size_t uv_udp_get_send_queue_count(const uv_udp_t* handle);
/*
@@ -712,6 +728,7 @@ UV_EXTERN int uv_pipe_getpeername(const uv_pipe_t* handle,
UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count);
UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle);
UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle);
+UV_EXTERN int uv_pipe_chmod(uv_pipe_t* handle, int flags);
struct uv_poll_s {
@@ -723,7 +740,8 @@ struct uv_poll_s {
enum uv_poll_event {
UV_READABLE = 1,
UV_WRITABLE = 2,
- UV_DISCONNECT = 4
+ UV_DISCONNECT = 4,
+ UV_PRIORITIZED = 8
};
UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd);
@@ -962,6 +980,7 @@ UV_EXTERN int uv_spawn(uv_loop_t* loop,
const uv_process_options_t* options);
UV_EXTERN int uv_process_kill(uv_process_t*, int signum);
UV_EXTERN int uv_kill(int pid, int signum);
+UV_EXTERN uv_pid_t uv_process_get_pid(const uv_process_t*);
/*
@@ -1038,6 +1057,7 @@ UV_EXTERN int uv_get_process_title(char* buffer, size_t size);
UV_EXTERN int uv_set_process_title(const char* title);
UV_EXTERN int uv_resident_set_memory(size_t* rss);
UV_EXTERN int uv_uptime(double* uptime);
+UV_EXTERN uv_os_fd_t uv_get_osfhandle(int fd);
typedef struct {
long tv_sec;
@@ -1069,6 +1089,8 @@ UV_EXTERN int uv_os_homedir(char* buffer, size_t* size);
UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size);
UV_EXTERN int uv_os_get_passwd(uv_passwd_t* pwd);
UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd);
+UV_EXTERN uv_pid_t uv_os_getpid(void);
+UV_EXTERN uv_pid_t uv_os_getppid(void);
UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);
@@ -1115,7 +1137,8 @@ typedef enum {
UV_FS_READLINK,
UV_FS_CHOWN,
UV_FS_FCHOWN,
- UV_FS_REALPATH
+ UV_FS_REALPATH,
+ UV_FS_COPYFILE
} uv_fs_type;
/* uv_fs_t is a subclass of uv_req_t. */
@@ -1131,6 +1154,12 @@ struct uv_fs_s {
UV_FS_PRIVATE_FIELDS
};
+UV_EXTERN uv_fs_type uv_fs_get_type(const uv_fs_t*);
+UV_EXTERN ssize_t uv_fs_get_result(const uv_fs_t*);
+UV_EXTERN void* uv_fs_get_ptr(const uv_fs_t*);
+UV_EXTERN const char* uv_fs_get_path(const uv_fs_t*);
+UV_EXTERN uv_stat_t* uv_fs_get_statbuf(uv_fs_t*);
+
UV_EXTERN void uv_fs_req_cleanup(uv_fs_t* req);
UV_EXTERN int uv_fs_close(uv_loop_t* loop,
uv_fs_t* req,
@@ -1160,6 +1189,18 @@ UV_EXTERN int uv_fs_write(uv_loop_t* loop,
unsigned int nbufs,
int64_t offset,
uv_fs_cb cb);
+/*
+ * This flag can be used with uv_fs_copyfile() to return an error if the
+ * destination already exists.
+ */
+#define UV_FS_COPYFILE_EXCL 0x0001
+
+UV_EXTERN int uv_fs_copyfile(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ int flags,
+ uv_fs_cb cb);
UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop,
uv_fs_t* req,
const char* path,
@@ -1393,6 +1434,21 @@ UV_EXTERN int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size
UV_EXTERN int uv_inet_ntop(int af, const void* src, char* dst, size_t size);
UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst);
+#if defined(IF_NAMESIZE)
+# define UV_IF_NAMESIZE (IF_NAMESIZE + 1)
+#elif defined(IFNAMSIZ)
+# define UV_IF_NAMESIZE (IFNAMSIZ + 1)
+#else
+# define UV_IF_NAMESIZE (16 + 1)
+#endif
+
+UV_EXTERN int uv_if_indextoname(unsigned int ifindex,
+ char* buffer,
+ size_t* size);
+UV_EXTERN int uv_if_indextoiid(unsigned int ifindex,
+ char* buffer,
+ size_t* size);
+
UV_EXTERN int uv_exepath(char* buffer, size_t* size);
UV_EXTERN int uv_cwd(char* buffer, size_t* size);
@@ -1412,6 +1468,7 @@ UV_EXTERN int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr);
UV_EXTERN const char* uv_dlerror(const uv_lib_t* lib);
UV_EXTERN int uv_mutex_init(uv_mutex_t* handle);
+UV_EXTERN int uv_mutex_init_recursive(uv_mutex_t* handle);
UV_EXTERN void uv_mutex_destroy(uv_mutex_t* handle);
UV_EXTERN void uv_mutex_lock(uv_mutex_t* handle);
UV_EXTERN int uv_mutex_trylock(uv_mutex_t* handle);
@@ -1484,6 +1541,8 @@ struct uv_loop_s {
UV_LOOP_PRIVATE_FIELDS
};
+UV_EXTERN void* uv_loop_get_data(const uv_loop_t*);
+UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data);
/* Don't export the private CPP symbols. */
#undef UV_HANDLE_TYPE_PRIVATE
diff --git a/Utilities/cmlibuv/src/threadpool.c b/Utilities/cmlibuv/src/threadpool.c
index 1089341..413d1c2 100644
--- a/Utilities/cmlibuv/src/threadpool.c
+++ b/Utilities/cmlibuv/src/threadpool.c
@@ -38,7 +38,6 @@ static uv_thread_t* threads;
static uv_thread_t default_threads[4];
static QUEUE exit_message;
static QUEUE wq;
-static volatile int initialized;
static void uv__cancelled(struct uv__work* w) {
@@ -53,7 +52,8 @@ static void worker(void* arg) {
struct uv__work* w;
QUEUE* q;
- (void) arg;
+ uv_sem_post((uv_sem_t*) arg);
+ arg = NULL;
for (;;) {
uv_mutex_lock(&mutex);
@@ -105,7 +105,7 @@ static void post(QUEUE* q) {
UV_DESTRUCTOR(static void cleanup(void)) {
unsigned int i;
- if (initialized == 0)
+ if (nthreads == 0)
return;
post(&exit_message);
@@ -122,7 +122,6 @@ UV_DESTRUCTOR(static void cleanup(void)) {
threads = NULL;
nthreads = 0;
- initialized = 0;
}
#endif
@@ -130,6 +129,7 @@ UV_DESTRUCTOR(static void cleanup(void)) {
static void init_threads(void) {
unsigned int i;
const char* val;
+ uv_sem_t sem;
nthreads = ARRAY_SIZE(default_threads);
val = getenv("UV_THREADPOOL_SIZE");
@@ -157,11 +157,17 @@ static void init_threads(void) {
QUEUE_INIT(&wq);
+ if (uv_sem_init(&sem, 0))
+ abort();
+
for (i = 0; i < nthreads; i++)
- if (uv_thread_create(threads + i, worker, NULL))
+ if (uv_thread_create(threads + i, worker, &sem))
abort();
- initialized = 1;
+ for (i = 0; i < nthreads; i++)
+ uv_sem_wait(&sem);
+
+ uv_sem_destroy(&sem);
}
diff --git a/Utilities/cmlibuv/src/unix/aix-common.c b/Utilities/cmlibuv/src/unix/aix-common.c
new file mode 100644
index 0000000..c2217fb
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/aix-common.c
@@ -0,0 +1,292 @@
+/* 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 <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utmp.h>
+#include <libgen.h>
+
+#include <sys/protosw.h>
+#include <procinfo.h>
+#include <sys/proc.h>
+#include <sys/procfs.h>
+
+#include <sys/poll.h>
+
+#include <sys/pollset.h>
+#include <ctype.h>
+
+#include <sys/mntctl.h>
+#include <sys/vmount.h>
+#include <limits.h>
+#include <strings.h>
+#include <sys/vnode.h>
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ uint64_t G = 1000000000;
+ timebasestruct_t t;
+ read_wall_time(&t, TIMEBASE_SZ);
+ time_base_to_time(&t, TIMEBASE_SZ);
+ return (uint64_t) t.tb_high * G + t.tb_low;
+}
+
+
+/*
+ * We could use a static buffer for the path manipulations that we need outside
+ * of the function, but this function could be called by multiple consumers and
+ * we don't want to potentially create a race condition in the use of snprintf.
+ * There is no direct way of getting the exe path in AIX - either through /procfs
+ * or through some libc APIs. The below approach is to parse the argv[0]'s pattern
+ * and use it in conjunction with PATH environment variable to craft one.
+ */
+int uv_exepath(char* buffer, size_t* size) {
+ int res;
+ char args[PATH_MAX];
+ char abspath[PATH_MAX];
+ size_t abspath_size;
+ struct procsinfo pi;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ pi.pi_pid = getpid();
+ res = getargs(&pi, sizeof(pi), args, sizeof(args));
+ if (res < 0)
+ return -EINVAL;
+
+ /*
+ * Possibilities for args:
+ * i) an absolute path such as: /home/user/myprojects/nodejs/node
+ * ii) a relative path such as: ./node or ../myprojects/nodejs/node
+ * iii) a bare filename such as "node", after exporting PATH variable
+ * to its location.
+ */
+
+ /* Case i) and ii) absolute or relative paths */
+ if (strchr(args, '/') != NULL) {
+ if (realpath(args, abspath) != abspath)
+ return -errno;
+
+ abspath_size = strlen(abspath);
+
+ *size -= 1;
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ return 0;
+ } else {
+ /* Case iii). Search PATH environment variable */
+ char trypath[PATH_MAX];
+ char *clonedpath = NULL;
+ char *token = NULL;
+ char *path = getenv("PATH");
+
+ if (path == NULL)
+ return -EINVAL;
+
+ clonedpath = uv__strdup(path);
+ if (clonedpath == NULL)
+ return -ENOMEM;
+
+ token = strtok(clonedpath, ":");
+ while (token != NULL) {
+ snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args);
+ if (realpath(trypath, abspath) == abspath) {
+ /* Check the match is executable */
+ if (access(abspath, X_OK) == 0) {
+ abspath_size = strlen(abspath);
+
+ *size -= 1;
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ uv__free(clonedpath);
+ return 0;
+ }
+ }
+ token = strtok(NULL, ":");
+ }
+ uv__free(clonedpath);
+
+ /* Out of tokens (path entries), and no match found */
+ return -EINVAL;
+ }
+}
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; ++i) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses,
+ int* count) {
+ uv_interface_address_t* address;
+ int sockfd, inet6, size = 1;
+ struct ifconf ifc;
+ struct ifreq *ifr, *p, flg;
+ struct sockaddr_dl* sa_addr;
+
+ *count = 0;
+
+ if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
+ return -errno;
+ }
+
+ if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) {
+ uv__close(sockfd);
+ return -errno;
+ }
+
+ ifc.ifc_req = (struct ifreq*)uv__malloc(size);
+ ifc.ifc_len = size;
+ if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
+ uv__close(sockfd);
+ return -errno;
+ }
+
+#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
+
+ /* Count all up and running ipv4/ipv6 addresses */
+ ifr = ifc.ifc_req;
+ while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
+ p = ifr;
+ ifr = (struct ifreq*)
+ ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
+
+ if (!(p->ifr_addr.sa_family == AF_INET6 ||
+ p->ifr_addr.sa_family == AF_INET))
+ continue;
+
+ memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
+ uv__close(sockfd);
+ return -errno;
+ }
+
+ if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
+ continue;
+
+ (*count)++;
+ }
+
+ /* Alloc the return interface structs */
+ *addresses = uv__malloc(*count * sizeof(uv_interface_address_t));
+ if (!(*addresses)) {
+ uv__close(sockfd);
+ return -ENOMEM;
+ }
+ address = *addresses;
+
+ ifr = ifc.ifc_req;
+ while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
+ p = ifr;
+ ifr = (struct ifreq*)
+ ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
+
+ if (!(p->ifr_addr.sa_family == AF_INET6 ||
+ p->ifr_addr.sa_family == AF_INET))
+ continue;
+
+ inet6 = (p->ifr_addr.sa_family == AF_INET6);
+
+ memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
+ uv__close(sockfd);
+ return -ENOSYS;
+ }
+
+ if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
+ continue;
+
+ /* All conditions above must match count loop */
+
+ address->name = uv__strdup(p->ifr_name);
+
+ if (inet6)
+ address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
+ else
+ address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
+
+ sa_addr = (struct sockaddr_dl*) &p->ifr_addr;
+ memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
+
+ if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) {
+ uv__close(sockfd);
+ return -ENOSYS;
+ }
+
+ if (inet6)
+ address->netmask.netmask6 = *((struct sockaddr_in6*) &p->ifr_addr);
+ else
+ address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr);
+
+ address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
+
+ address++;
+ }
+
+#undef ADDR_SIZE
+
+ uv__close(sockfd);
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+
+ for (i = 0; i < count; ++i) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
diff --git a/Utilities/cmlibuv/src/unix/aix.c b/Utilities/cmlibuv/src/unix/aix.c
index 388c9cc..fd41309 100644
--- a/Utilities/cmlibuv/src/unix/aix.c
+++ b/Utilities/cmlibuv/src/unix/aix.c
@@ -1,4 +1,5 @@
/* Copyright Joyent, Inc. and other Node 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
@@ -64,11 +65,18 @@
#define RDWR_BUF_SIZE 4096
#define EQ(a,b) (strcmp(a,b) == 0)
+static uv_mutex_t process_title_mutex;
+static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
static void* args_mem = NULL;
static char** process_argv = NULL;
static int process_argc = 0;
static char* process_title_ptr = NULL;
+static void init_process_title_mutex_once(void) {
+ uv_mutex_init(&process_title_mutex);
+}
+
+
int uv__platform_loop_init(uv_loop_t* loop) {
loop->fs_fd = -1;
@@ -316,104 +324,6 @@ update_timeout:
}
-uint64_t uv__hrtime(uv_clocktype_t type) {
- uint64_t G = 1000000000;
- timebasestruct_t t;
- read_wall_time(&t, TIMEBASE_SZ);
- time_base_to_time(&t, TIMEBASE_SZ);
- return (uint64_t) t.tb_high * G + t.tb_low;
-}
-
-
-/*
- * We could use a static buffer for the path manipulations that we need outside
- * of the function, but this function could be called by multiple consumers and
- * we don't want to potentially create a race condition in the use of snprintf.
- * There is no direct way of getting the exe path in AIX - either through /procfs
- * or through some libc APIs. The below approach is to parse the argv[0]'s pattern
- * and use it in conjunction with PATH environment variable to craft one.
- */
-int uv_exepath(char* buffer, size_t* size) {
- int res;
- char args[PATH_MAX];
- char abspath[PATH_MAX];
- size_t abspath_size;
- struct procsinfo pi;
-
- if (buffer == NULL || size == NULL || *size == 0)
- return -EINVAL;
-
- pi.pi_pid = getpid();
- res = getargs(&pi, sizeof(pi), args, sizeof(args));
- if (res < 0)
- return -EINVAL;
-
- /*
- * Possibilities for args:
- * i) an absolute path such as: /home/user/myprojects/nodejs/node
- * ii) a relative path such as: ./node or ../myprojects/nodejs/node
- * iii) a bare filename such as "node", after exporting PATH variable
- * to its location.
- */
-
- /* Case i) and ii) absolute or relative paths */
- if (strchr(args, '/') != NULL) {
- if (realpath(args, abspath) != abspath)
- return -errno;
-
- abspath_size = strlen(abspath);
-
- *size -= 1;
- if (*size > abspath_size)
- *size = abspath_size;
-
- memcpy(buffer, abspath, *size);
- buffer[*size] = '\0';
-
- return 0;
- } else {
- /* Case iii). Search PATH environment variable */
- char trypath[PATH_MAX];
- char *clonedpath = NULL;
- char *token = NULL;
- char *path = getenv("PATH");
-
- if (path == NULL)
- return -EINVAL;
-
- clonedpath = uv__strdup(path);
- if (clonedpath == NULL)
- return -ENOMEM;
-
- token = strtok(clonedpath, ":");
- while (token != NULL) {
- snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args);
- if (realpath(trypath, abspath) == abspath) {
- /* Check the match is executable */
- if (access(abspath, X_OK) == 0) {
- abspath_size = strlen(abspath);
-
- *size -= 1;
- if (*size > abspath_size)
- *size = abspath_size;
-
- memcpy(buffer, abspath, *size);
- buffer[*size] = '\0';
-
- uv__free(clonedpath);
- return 0;
- }
- }
- token = strtok(NULL, ":");
- }
- uv__free(clonedpath);
-
- /* Out of tokens (path entries), and no match found */
- return -EINVAL;
- }
-}
-
-
uint64_t uv_get_free_memory(void) {
perfstat_memory_total_t mem_total;
int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
@@ -855,6 +765,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
uv__io_init(&handle->event_watcher, uv__ahafs_event, fd);
handle->path = uv__strdup(filename);
handle->cb = cb;
+ handle->dir_filename = NULL;
uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
@@ -952,6 +863,9 @@ int uv_set_process_title(const char* title) {
if (new_title == NULL)
return -ENOMEM;
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
/* If this is the first time this is set,
* don't free and set argv[1] to NULL.
*/
@@ -964,6 +878,8 @@ int uv_set_process_title(const char* title) {
if (process_argc > 1)
process_argv[1] = NULL;
+ uv_mutex_unlock(&process_title_mutex);
+
return 0;
}
@@ -976,8 +892,13 @@ int uv_get_process_title(char* buffer, size_t size) {
else if (size <= len)
return -ENOBUFS;
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
memcpy(buffer, process_argv[0], len + 1);
+ uv_mutex_unlock(&process_title_mutex);
+
return 0;
}
@@ -1017,6 +938,7 @@ int uv_uptime(double* uptime) {
size_t entries = 0;
time_t boot_time;
+ boot_time = 0;
utmpname(UTMP_FILE);
setutent();
@@ -1093,130 +1015,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
}
-void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
- int i;
-
- for (i = 0; i < count; ++i) {
- uv__free(cpu_infos[i].model);
- }
-
- uv__free(cpu_infos);
-}
-
-
-int uv_interface_addresses(uv_interface_address_t** addresses,
- int* count) {
- uv_interface_address_t* address;
- int sockfd, size = 1;
- struct ifconf ifc;
- struct ifreq *ifr, *p, flg;
-
- *count = 0;
-
- if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
- return -errno;
- }
-
- if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) {
- uv__close(sockfd);
- return -errno;
- }
-
- ifc.ifc_req = (struct ifreq*)uv__malloc(size);
- ifc.ifc_len = size;
- if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
- uv__close(sockfd);
- return -errno;
- }
-
-#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
-
- /* Count all up and running ipv4/ipv6 addresses */
- ifr = ifc.ifc_req;
- while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
- p = ifr;
- ifr = (struct ifreq*)
- ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
-
- if (!(p->ifr_addr.sa_family == AF_INET6 ||
- p->ifr_addr.sa_family == AF_INET))
- continue;
-
- memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
- if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
- uv__close(sockfd);
- return -errno;
- }
-
- if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
- continue;
-
- (*count)++;
- }
-
- /* Alloc the return interface structs */
- *addresses = (uv_interface_address_t*)
- uv__malloc(*count * sizeof(uv_interface_address_t));
- if (!(*addresses)) {
- uv__close(sockfd);
- return -ENOMEM;
- }
- address = *addresses;
-
- ifr = ifc.ifc_req;
- while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
- p = ifr;
- ifr = (struct ifreq*)
- ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
-
- if (!(p->ifr_addr.sa_family == AF_INET6 ||
- p->ifr_addr.sa_family == AF_INET))
- continue;
-
- memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
- if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
- uv__close(sockfd);
- return -ENOSYS;
- }
-
- if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
- continue;
-
- /* All conditions above must match count loop */
-
- address->name = uv__strdup(p->ifr_name);
-
- if (p->ifr_addr.sa_family == AF_INET6) {
- address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
- } else {
- address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
- }
-
- /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
-
- address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
-
- address++;
- }
-
-#undef ADDR_SIZE
-
- uv__close(sockfd);
- return 0;
-}
-
-
-void uv_free_interface_addresses(uv_interface_address_t* addresses,
- int count) {
- int i;
-
- for (i = 0; i < count; ++i) {
- uv__free(addresses[i].name);
- }
-
- uv__free(addresses);
-}
-
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct pollfd* events;
uintptr_t i;
diff --git a/Utilities/cmlibuv/src/unix/android-ifaddrs.c b/Utilities/cmlibuv/src/unix/android-ifaddrs.c
index 30f681b..bf30b14 100644
--- a/Utilities/cmlibuv/src/unix/android-ifaddrs.c
+++ b/Utilities/cmlibuv/src/unix/android-ifaddrs.c
@@ -43,9 +43,10 @@ typedef struct NetlinkList
unsigned int m_size;
} NetlinkList;
-static int netlink_socket(void)
+static int netlink_socket(pid_t *p_pid)
{
struct sockaddr_nl l_addr;
+ socklen_t l_len;
int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if(l_socket < 0)
@@ -61,6 +62,14 @@ static int netlink_socket(void)
return -1;
}
+ l_len = sizeof(l_addr);
+ if(getsockname(l_socket, (struct sockaddr *)&l_addr, &l_len) < 0)
+ {
+ close(l_socket);
+ return -1;
+ }
+ *p_pid = l_addr.nl_pid;
+
return l_socket;
}
@@ -128,7 +137,7 @@ static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
}
}
-static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
+static struct nlmsghdr *getNetlinkResponse(int p_socket, pid_t p_pid, int *p_size, int *p_done)
{
size_t l_size = 4096;
void *l_buffer = NULL;
@@ -153,11 +162,10 @@ static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_don
}
if(l_read >= 0)
{
- pid_t l_pid = getpid();
struct nlmsghdr *l_hdr;
for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
{
- if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+ if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
{
continue;
}
@@ -207,7 +215,7 @@ static void freeResultList(NetlinkList *p_list)
}
}
-static NetlinkList *getResultList(int p_socket, int p_request)
+static NetlinkList *getResultList(int p_socket, int p_request, pid_t p_pid)
{
int l_size;
int l_done;
@@ -227,7 +235,7 @@ static NetlinkList *getResultList(int p_socket, int p_request)
{
NetlinkList *l_item;
- struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
+ struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, p_pid, &l_size, &l_done);
/* Error */
if(!l_hdr)
{
@@ -449,7 +457,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
char *l_name;
char *l_addr;
- for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+ for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
if(l_info->ifa_family == AF_PACKET)
@@ -471,7 +479,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
break;
case IFA_LABEL:
- l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
+ l_nameSize += NLMSG_ALIGN(l_rtaDataSize + 1);
break;
default:
break;
@@ -496,7 +504,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
}
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
- for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+ for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
void *l_rtaData = RTA_DATA(l_rta);
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
@@ -559,7 +567,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
{
unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
- char l_mask[16] = {0};
+ unsigned char l_mask[16] = {0};
unsigned i;
for(i=0; i<(l_prefix/8); ++i)
{
@@ -578,18 +586,17 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
return 0;
}
-static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
+static int interpretLinks(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
{
int l_numLinks = 0;
- pid_t l_pid = getpid();
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
{
unsigned int l_nlsize = p_netlinkList->m_size;
struct nlmsghdr *l_hdr;
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
{
- if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+ if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
{
continue;
}
@@ -612,16 +619,15 @@ static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifadd
return l_numLinks;
}
-static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
+static int interpretAddrs(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
{
- pid_t l_pid = getpid();
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
{
unsigned int l_nlsize = p_netlinkList->m_size;
struct nlmsghdr *l_hdr;
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
{
- if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+ if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
{
continue;
}
@@ -648,6 +654,7 @@ int getifaddrs(struct ifaddrs **ifap)
int l_socket;
int l_result;
int l_numLinks;
+ pid_t l_pid;
NetlinkList *l_linkResults;
NetlinkList *l_addrResults;
@@ -657,20 +664,20 @@ int getifaddrs(struct ifaddrs **ifap)
}
*ifap = NULL;
- l_socket = netlink_socket();
+ l_socket = netlink_socket(&l_pid);
if(l_socket < 0)
{
return -1;
}
- l_linkResults = getResultList(l_socket, RTM_GETLINK);
+ l_linkResults = getResultList(l_socket, RTM_GETLINK, l_pid);
if(!l_linkResults)
{
close(l_socket);
return -1;
}
- l_addrResults = getResultList(l_socket, RTM_GETADDR);
+ l_addrResults = getResultList(l_socket, RTM_GETADDR, l_pid);
if(!l_addrResults)
{
close(l_socket);
@@ -679,8 +686,8 @@ int getifaddrs(struct ifaddrs **ifap)
}
l_result = 0;
- l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
- if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)
+ l_numLinks = interpretLinks(l_socket, l_pid, l_linkResults, ifap);
+ if(l_numLinks == -1 || interpretAddrs(l_socket, l_pid, l_addrResults, ifap, l_numLinks) == -1)
{
l_result = -1;
}
diff --git a/Utilities/cmlibuv/src/unix/atomic-ops.h b/Utilities/cmlibuv/src/unix/atomic-ops.h
index 9dac255..7cac1f9 100644
--- a/Utilities/cmlibuv/src/unix/atomic-ops.h
+++ b/Utilities/cmlibuv/src/unix/atomic-ops.h
@@ -20,7 +20,6 @@
#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
#include <atomic.h>
-#define __sync_val_compare_and_swap(p, o, n) atomic_cas_ptr(p, o, n)
#endif
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval));
@@ -49,6 +48,8 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
return oldval;
else
return op4;
+#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+ return atomic_cas_uint(ptr, oldval, newval);
#else
return __sync_val_compare_and_swap(ptr, oldval, newval);
#endif
@@ -83,6 +84,8 @@ UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) {
return oldval;
else
return op4;
+#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+ return atomic_cas_ulong(ptr, oldval, newval);
#else
return __sync_val_compare_and_swap(ptr, oldval, newval);
#endif
diff --git a/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c b/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c
index 4147894..ea3166c 100644
--- a/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c
+++ b/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c
@@ -31,11 +31,20 @@
#include <net/if_dl.h>
#endif
-static int uv__ifaddr_exclude(struct ifaddrs *ent) {
+static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
return 1;
if (ent->ifa_addr == NULL)
return 1;
+#if !defined(__CYGWIN__) && !defined(__MSYS__)
+ /*
+ * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, just see whether `sa_family`
+ * equals to `AF_LINK` or not. Otherwise, the result depends on the operation
+ * system with `AF_LINK` or `PF_INET`.
+ */
+ if (exclude_type == UV__EXCLUDE_IFPHYS)
+ return (ent->ifa_addr->sa_family != AF_LINK);
+#endif
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
/*
* On BSD getifaddrs returns information related to the raw underlying
@@ -43,7 +52,11 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent) {
*/
if (ent->ifa_addr->sa_family == AF_LINK)
return 1;
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
+#elif defined(__NetBSD__)
+ if (ent->ifa_addr->sa_family != PF_INET &&
+ ent->ifa_addr->sa_family != PF_INET6)
+ return 1;
+#elif defined(__OpenBSD__)
if (ent->ifa_addr->sa_family != PF_INET)
return 1;
#endif
@@ -63,7 +76,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
/* Count the number of interfaces */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
- if (uv__ifaddr_exclude(ent))
+ if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
continue;
(*count)++;
}
@@ -78,7 +91,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
address = *addresses;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
- if (uv__ifaddr_exclude(ent))
+ if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
continue;
address->name = uv__strdup(ent->ifa_name);
@@ -102,7 +115,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
/* Fill in physical addresses for each interface */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
- if (uv__ifaddr_exclude(ent))
+ if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
continue;
address = *addresses;
diff --git a/Utilities/cmlibuv/src/unix/core.c b/Utilities/cmlibuv/src/unix/core.c
index 30cdaef..c7e431e 100644
--- a/Utilities/cmlibuv/src/unix/core.c
+++ b/Utilities/cmlibuv/src/unix/core.c
@@ -28,7 +28,6 @@
#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>
@@ -59,13 +58,19 @@
#if defined(__DragonFly__) || \
defined(__FreeBSD__) || \
- defined(__FreeBSD_kernel__)
+ defined(__FreeBSD_kernel__) || \
+ defined(__NetBSD__)
# include <sys/sysctl.h>
# include <sys/filio.h>
# include <sys/wait.h>
# define UV__O_CLOEXEC O_CLOEXEC
# if defined(__FreeBSD__) && __FreeBSD__ >= 10
# define uv__accept4 accept4
+# endif
+# if defined(__NetBSD__)
+# define uv__accept4(a, b, c, d) paccept((a), (b), (c), NULL, (d))
+# endif
+# if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__)
# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
# define UV__SOCK_CLOEXEC SOCK_CLOEXEC
# endif
@@ -82,6 +87,10 @@
#include <sys/ioctl.h>
#endif
+#if !defined(__MVS__)
+#include <sys/param.h> /* MAXHOSTNAMELEN on Linux and the BSDs */
+#endif
+
/* Fallback for the maximum hostname length */
#ifndef MAXHOSTNAMELEN
# define MAXHOSTNAMELEN 256
@@ -459,7 +468,9 @@ int uv__accept(int sockfd) {
assert(sockfd >= 0);
while (1) {
-#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10)
+#if defined(__linux__) || \
+ (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \
+ defined(__NetBSD__)
static int no_accept4;
if (no_accept4)
@@ -835,7 +846,7 @@ void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) {
void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
- assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP)));
+ assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
assert(0 != events);
assert(w->fd >= 0);
assert(w->fd < INT_MAX);
@@ -863,7 +874,7 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
- assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP)));
+ assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
assert(0 != events);
if (w->fd == -1)
@@ -895,7 +906,7 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
- uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP);
+ uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
QUEUE_REMOVE(&w->pending_queue);
/* Remove stale events for this file descriptor */
@@ -910,7 +921,7 @@ void uv__io_feed(uv_loop_t* loop, uv__io_t* w) {
int uv__io_active(const uv__io_t* w, unsigned int events) {
- assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP)));
+ assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
assert(0 != events);
return 0 != (w->pevents & events);
}
@@ -985,7 +996,7 @@ int uv__open_cloexec(const char* path, int flags) {
int uv__dup2_cloexec(int oldfd, int newfd) {
int r;
-#if defined(__FreeBSD__) && __FreeBSD__ >= 10
+#if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__)
r = dup3(oldfd, newfd, O_CLOEXEC);
if (r == -1)
return -errno;
@@ -1289,6 +1300,9 @@ int uv_os_setenv(const char* name, const char* value) {
int uv_os_unsetenv(const char* name) {
+ if (name == NULL)
+ return -EINVAL;
+
if (unsetenv(name) != 0)
return -errno;
@@ -1324,3 +1338,18 @@ int uv_os_gethostname(char* buffer, size_t* size) {
*size = len;
return 0;
}
+
+
+uv_os_fd_t uv_get_osfhandle(int fd) {
+ return fd;
+}
+
+
+uv_pid_t uv_os_getpid(void) {
+ return getpid();
+}
+
+
+uv_pid_t uv_os_getppid(void) {
+ return getppid();
+}
diff --git a/Utilities/cmlibuv/src/unix/freebsd.c b/Utilities/cmlibuv/src/unix/freebsd.c
index e52ae99..f2b3f24 100644
--- a/Utilities/cmlibuv/src/unix/freebsd.c
+++ b/Utilities/cmlibuv/src/unix/freebsd.c
@@ -25,7 +25,6 @@
#include <string.h>
#include <errno.h>
-#include <kvm.h>
#include <paths.h>
#include <sys/user.h>
#include <sys/types.h>
@@ -48,9 +47,16 @@
# define CP_INTR 4
#endif
+static uv_mutex_t process_title_mutex;
+static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
static char *process_title;
+static void init_process_title_mutex_once(void) {
+ uv_mutex_init(&process_title_mutex);
+}
+
+
int uv__platform_loop_init(uv_loop_t* loop) {
return uv__kqueue_init(loop);
}
@@ -161,9 +167,20 @@ char** uv_setup_args(int argc, char** argv) {
int uv_set_process_title(const char* title) {
int oid[4];
+ char* new_title;
+
+ new_title = uv__strdup(title);
+
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
+ if (process_title == NULL) {
+ uv_mutex_unlock(&process_title_mutex);
+ return -ENOMEM;
+ }
uv__free(process_title);
- process_title = uv__strdup(title);
+ process_title = new_title;
oid[0] = CTL_KERN;
oid[1] = KERN_PROC;
@@ -177,6 +194,8 @@ int uv_set_process_title(const char* title) {
process_title,
strlen(process_title) + 1);
+ uv_mutex_unlock(&process_title_mutex);
+
return 0;
}
@@ -187,51 +206,54 @@ int uv_get_process_title(char* buffer, size_t size) {
if (buffer == NULL || size == 0)
return -EINVAL;
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
if (process_title) {
len = strlen(process_title) + 1;
- if (size < len)
+ if (size < len) {
+ uv_mutex_unlock(&process_title_mutex);
return -ENOBUFS;
+ }
memcpy(buffer, process_title, len);
} else {
len = 0;
}
+ uv_mutex_unlock(&process_title_mutex);
+
buffer[len] = '\0';
return 0;
}
-
int uv_resident_set_memory(size_t* rss) {
- kvm_t *kd = NULL;
- struct kinfo_proc *kinfo = NULL;
- pid_t pid;
- int nprocs;
- size_t page_size = getpagesize();
+ struct kinfo_proc kinfo;
+ size_t page_size;
+ size_t kinfo_size;
+ int mib[4];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = getpid();
- pid = getpid();
+ kinfo_size = sizeof(kinfo);
- kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
- if (kd == NULL) goto error;
+ if (sysctl(mib, 4, &kinfo, &kinfo_size, NULL, 0))
+ return -errno;
- kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, &nprocs);
- if (kinfo == NULL) goto error;
+ page_size = getpagesize();
#ifdef __DragonFly__
- *rss = kinfo->kp_vm_rssize * page_size;
+ *rss = kinfo.kp_vm_rssize * page_size;
#else
- *rss = kinfo->ki_rssize * page_size;
+ *rss = kinfo.ki_rssize * page_size;
#endif
- kvm_close(kd);
-
return 0;
-
-error:
- if (kd) kvm_close(kd);
- return -EPERM;
}
@@ -254,6 +276,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
uv_cpu_info_t* cpu_info;
const char* maxcpus_key;
const char* cptimes_key;
+ const char* model_key;
char model[512];
long* cp_times;
int numcpus;
@@ -272,8 +295,20 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
cptimes_key = "kern.cp_times";
#endif
+#if defined(__arm__) || defined(__aarch64__)
+ /* The key hw.model and hw.clockrate are not available on FreeBSD ARM. */
+ model_key = "hw.machine";
+ cpuspeed = 0;
+#else
+ model_key = "hw.model";
+
+ size = sizeof(cpuspeed);
+ if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0))
+ return -errno;
+#endif
+
size = sizeof(model);
- if (sysctlbyname("hw.model", &model, &size, NULL, 0))
+ if (sysctlbyname(model_key, &model, &size, NULL, 0))
return -errno;
size = sizeof(numcpus);
@@ -286,12 +321,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
*count = numcpus;
- size = sizeof(cpuspeed);
- if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) {
- uv__free(*cpu_infos);
- return -errno;
- }
-
/* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of
* ncpu.
*/
diff --git a/Utilities/cmlibuv/src/unix/fs.c b/Utilities/cmlibuv/src/unix/fs.c
index 82c91ef..0a4c183 100644
--- a/Utilities/cmlibuv/src/unix/fs.c
+++ b/Utilities/cmlibuv/src/unix/fs.c
@@ -60,8 +60,14 @@
# include <sys/sendfile.h>
#endif
+#if defined(__APPLE__)
+# include <copyfile.h>
+#endif
+
#define INIT(subtype) \
do { \
+ if (req == NULL) \
+ return -EINVAL; \
req->type = UV_FS; \
if (cb != NULL) \
uv__req_init(loop, req, UV_FS); \
@@ -126,26 +132,33 @@
while (0)
-static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
-#if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
- return fdatasync(req->file);
-#elif defined(__APPLE__)
+static ssize_t uv__fs_fsync(uv_fs_t* req) {
+#if defined(__APPLE__)
/* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache
* to the drive platters. This is in contrast to Linux's fdatasync and fsync
* which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent
- * for flushing buffered data to permanent storage.
+ * for flushing buffered data to permanent storage. If F_FULLFSYNC is not
+ * supported by the file system we should fall back to fsync(). This is the
+ * same approach taken by sqlite.
*/
- return fcntl(req->file, F_FULLFSYNC);
+ int r;
+
+ r = fcntl(req->file, F_FULLFSYNC);
+ if (r != 0 && errno == ENOTTY)
+ r = fsync(req->file);
+ return r;
#else
return fsync(req->file);
#endif
}
-static ssize_t uv__fs_fsync(uv_fs_t* req) {
-#if defined(__APPLE__)
- /* See the comment in uv__fs_fdatasync. */
- return fcntl(req->file, F_FULLFSYNC);
+static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
+#if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
+ return fdatasync(req->file);
+#elif defined(__APPLE__)
+ /* See the comment in uv__fs_fsync. */
+ return uv__fs_fsync(req);
#else
return fsync(req->file);
#endif
@@ -442,7 +455,12 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
return -1;
}
+#if defined(__MVS__)
+ len = os390_readlink(req->path, buf, len);
+#else
len = readlink(req->path, buf, len);
+#endif
+
if (len == -1) {
uv__free(buf);
@@ -776,6 +794,118 @@ done:
return r;
}
+static ssize_t uv__fs_copyfile(uv_fs_t* req) {
+#if defined(__APPLE__) && !TARGET_OS_IPHONE
+ /* On macOS, use the native copyfile(3). */
+ copyfile_flags_t flags;
+
+ flags = COPYFILE_ALL;
+
+ if (req->flags & UV_FS_COPYFILE_EXCL)
+ flags |= COPYFILE_EXCL;
+
+ return copyfile(req->path, req->new_path, NULL, flags);
+#else
+ uv_fs_t fs_req;
+ uv_file srcfd;
+ uv_file dstfd;
+ struct stat statsbuf;
+ int dst_flags;
+ int result;
+ int err;
+ size_t bytes_to_send;
+ int64_t in_offset;
+
+ dstfd = -1;
+ err = 0;
+
+ /* Open the source file. */
+ srcfd = uv_fs_open(NULL, &fs_req, req->path, O_RDONLY, 0, NULL);
+ uv_fs_req_cleanup(&fs_req);
+
+ if (srcfd < 0)
+ return srcfd;
+
+ /* Get the source file's mode. */
+ if (fstat(srcfd, &statsbuf)) {
+ err = -errno;
+ goto out;
+ }
+
+ dst_flags = O_WRONLY | O_CREAT | O_TRUNC;
+
+ if (req->flags & UV_FS_COPYFILE_EXCL)
+ dst_flags |= O_EXCL;
+
+ /* Open the destination file. */
+ dstfd = uv_fs_open(NULL,
+ &fs_req,
+ req->new_path,
+ dst_flags,
+ statsbuf.st_mode,
+ NULL);
+ uv_fs_req_cleanup(&fs_req);
+
+ if (dstfd < 0) {
+ err = dstfd;
+ goto out;
+ }
+
+ if (fchmod(dstfd, statsbuf.st_mode) == -1) {
+ err = -errno;
+ goto out;
+ }
+
+ bytes_to_send = statsbuf.st_size;
+ in_offset = 0;
+ while (bytes_to_send != 0) {
+ err = uv_fs_sendfile(NULL,
+ &fs_req,
+ dstfd,
+ srcfd,
+ in_offset,
+ bytes_to_send,
+ NULL);
+ uv_fs_req_cleanup(&fs_req);
+ if (err < 0)
+ break;
+ bytes_to_send -= fs_req.result;
+ in_offset += fs_req.result;
+ }
+
+out:
+ if (err < 0)
+ result = err;
+ else
+ result = 0;
+
+ /* Close the source file. */
+ err = uv__close_nocheckstdio(srcfd);
+
+ /* Don't overwrite any existing errors. */
+ if (err != 0 && result == 0)
+ result = err;
+
+ /* Close the destination file if it is open. */
+ if (dstfd >= 0) {
+ err = uv__close_nocheckstdio(dstfd);
+
+ /* Don't overwrite any existing errors. */
+ if (err != 0 && result == 0)
+ result = err;
+
+ /* Remove the destination file if something went wrong. */
+ if (result != 0) {
+ uv_fs_unlink(NULL, &fs_req, req->new_path, NULL);
+ /* Ignore the unlink return value, as an error already happened. */
+ uv_fs_req_cleanup(&fs_req);
+ }
+ }
+
+ return result;
+#endif
+}
+
static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
dst->st_dev = src->st_dev;
dst->st_mode = src->st_mode;
@@ -956,6 +1086,7 @@ static void uv__fs_work(struct uv__work* w) {
X(CHMOD, chmod(req->path, req->mode));
X(CHOWN, chown(req->path, req->uid, req->gid));
X(CLOSE, close(req->file));
+ X(COPYFILE, uv__fs_copyfile(req));
X(FCHMOD, fchmod(req->file, req->mode));
X(FCHOWN, fchown(req->file, req->uid, req->gid));
X(FDATASYNC, uv__fs_fdatasync(req));
@@ -1196,10 +1327,11 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
unsigned int nbufs,
int64_t off,
uv_fs_cb cb) {
+ INIT(READ);
+
if (bufs == NULL || nbufs == 0)
return -EINVAL;
- INIT(READ);
req->file = file;
req->nbufs = nbufs;
@@ -1334,10 +1466,11 @@ int uv_fs_write(uv_loop_t* loop,
unsigned int nbufs,
int64_t off,
uv_fs_cb cb) {
+ INIT(WRITE);
+
if (bufs == NULL || nbufs == 0)
return -EINVAL;
- INIT(WRITE);
req->file = file;
req->nbufs = nbufs;
@@ -1359,6 +1492,9 @@ int uv_fs_write(uv_loop_t* loop,
void uv_fs_req_cleanup(uv_fs_t* req) {
+ if (req == NULL)
+ return;
+
/* Only necessary for asychronous requests, i.e., requests with a callback.
* Synchronous ones don't copy their arguments and have req->path and
* req->new_path pointing to user-owned memory. UV_FS_MKDTEMP is the
@@ -1377,3 +1513,20 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
uv__free(req->ptr);
req->ptr = NULL;
}
+
+
+int uv_fs_copyfile(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ int flags,
+ uv_fs_cb cb) {
+ INIT(COPYFILE);
+
+ if (flags & ~UV_FS_COPYFILE_EXCL)
+ return -EINVAL;
+
+ PATH2;
+ req->flags = flags;
+ POST;
+}
diff --git a/Utilities/cmlibuv/src/unix/fsevents.c b/Utilities/cmlibuv/src/unix/fsevents.c
index 643e233..3883740 100644
--- a/Utilities/cmlibuv/src/unix/fsevents.c
+++ b/Utilities/cmlibuv/src/unix/fsevents.c
@@ -230,6 +230,7 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
uv_loop_t* loop;
uv__cf_loop_state_t* state;
uv__fsevents_event_t* event;
+ FSEventStreamEventFlags flags;
QUEUE head;
loop = info;
@@ -245,8 +246,10 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
/* Process and filter out events */
for (i = 0; i < numEvents; i++) {
+ flags = eventFlags[i];
+
/* Ignore system events */
- if (eventFlags[i] & kFSEventsSystem)
+ if (flags & kFSEventsSystem)
continue;
path = paths[i];
@@ -271,6 +274,9 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
/* Ignore events with path equal to directory itself */
if (len == 0)
continue;
+#else
+ if (len == 0 && (flags & kFSEventStreamEventFlagItemIsDir))
+ continue;
#endif /* MAC_OS_X_VERSION_10_7 */
/* Do not emit events from subdirectories (without option set) */
@@ -291,12 +297,24 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
memset(event, 0, sizeof(*event));
memcpy(event->path, path, len + 1);
+ event->events = UV_RENAME;
- if ((eventFlags[i] & kFSEventsModified) != 0 &&
- (eventFlags[i] & kFSEventsRenamed) == 0)
+#ifdef MAC_OS_X_VERSION_10_7
+ if (0 != (flags & kFSEventsModified) &&
+ 0 == (flags & kFSEventsRenamed)) {
+ event->events = UV_CHANGE;
+ }
+#else
+ if (0 != (flags & kFSEventsModified) &&
+ 0 != (flags & kFSEventStreamEventFlagItemIsDir) &&
+ 0 == (flags & kFSEventStreamEventFlagItemRenamed)) {
event->events = UV_CHANGE;
- else
- event->events = UV_RENAME;
+ }
+ if (0 == (flags & kFSEventStreamEventFlagItemIsDir) &&
+ 0 == (flags & kFSEventStreamEventFlagItemRenamed)) {
+ event->events = UV_CHANGE;
+ }
+#endif /* MAC_OS_X_VERSION_10_7 */
QUEUE_INSERT_TAIL(&head, &event->member);
}
diff --git a/Utilities/cmlibuv/src/unix/getaddrinfo.c b/Utilities/cmlibuv/src/unix/getaddrinfo.c
index 2049aea..0185971 100644
--- a/Utilities/cmlibuv/src/unix/getaddrinfo.c
+++ b/Utilities/cmlibuv/src/unix/getaddrinfo.c
@@ -32,6 +32,7 @@
#include <stddef.h> /* NULL */
#include <stdlib.h>
#include <string.h>
+#include <net/if.h> /* if_indextoname() */
/* EAI_* constants. */
#include <netdb.h>
@@ -200,3 +201,32 @@ void uv_freeaddrinfo(struct addrinfo* ai) {
if (ai)
freeaddrinfo(ai);
}
+
+
+int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
+ char ifname_buf[UV_IF_NAMESIZE];
+ size_t len;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return UV_EINVAL;
+
+ if (if_indextoname(ifindex, ifname_buf) == NULL)
+ return -errno;
+
+ len = strnlen(ifname_buf, sizeof(ifname_buf));
+
+ if (*size <= len) {
+ *size = len + 1;
+ return UV_ENOBUFS;
+ }
+
+ memcpy(buffer, ifname_buf, len);
+ buffer[len] = '\0';
+ *size = len;
+
+ return 0;
+}
+
+int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
+ return uv_if_indextoname(ifindex, buffer, size);
+}
diff --git a/Utilities/cmlibuv/src/unix/ibmi.c b/Utilities/cmlibuv/src/unix/ibmi.c
new file mode 100644
index 0000000..c19e2fc
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/ibmi.c
@@ -0,0 +1,112 @@
+/* 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 <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utmp.h>
+#include <libgen.h>
+
+#include <sys/protosw.h>
+#include <procinfo.h>
+#include <sys/proc.h>
+#include <sys/procfs.h>
+
+#include <ctype.h>
+
+#include <sys/mntctl.h>
+#include <sys/vmount.h>
+#include <limits.h>
+#include <strings.h>
+#include <sys/vnode.h>
+
+uint64_t uv_get_free_memory(void) {
+ return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
+}
+
+
+void uv_loadavg(double avg[3]) {
+ avg[0] = avg[1] = avg[2] = 0;
+ return;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ return UV_ENOSYS;
+}
+
+
+int uv_uptime(double* uptime) {
+ return UV_ENOSYS;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ unsigned int numcpus, idx = 0;
+ uv_cpu_info_t* cpu_info;
+
+ *cpu_infos = NULL;
+ *count = 0;
+
+ numcpus = sysconf(_SC_NPROCESSORS_ONLN);
+
+ *cpu_infos = uv__malloc(numcpus * sizeof(uv_cpu_info_t));
+ if (!*cpu_infos) {
+ return -ENOMEM;
+ }
+
+ cpu_info = *cpu_infos;
+ for (idx = 0; idx < numcpus; idx++) {
+ cpu_info->speed = 0;
+ cpu_info->model = uv__strdup("unknown");
+ cpu_info->cpu_times.user = 0;
+ cpu_info->cpu_times.sys = 0;
+ cpu_info->cpu_times.idle = 0;
+ cpu_info->cpu_times.irq = 0;
+ cpu_info->cpu_times.nice = 0;
+ cpu_info++;
+ }
+ *count = numcpus;
+
+ return 0;
+}
diff --git a/Utilities/cmlibuv/src/unix/internal.h b/Utilities/cmlibuv/src/unix/internal.h
index e9f7908..9cc87f0 100644
--- a/Utilities/cmlibuv/src/unix/internal.h
+++ b/Utilities/cmlibuv/src/unix/internal.h
@@ -120,6 +120,12 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
# define UV__POLLRDHUP 0x2000
#endif
+#ifdef POLLPRI
+# define UV__POLLPRI POLLPRI
+#else
+# define UV__POLLPRI 0
+#endif
+
#if !defined(O_CLOEXEC) && defined(__FreeBSD__)
/*
* It may be that we are just missing `__POSIX_VISIBLE >= 200809`.
@@ -155,6 +161,12 @@ enum {
UV_LOOP_BLOCK_SIGPROF = 1
};
+/* flags of excluding ifaddr */
+enum {
+ UV__EXCLUDE_IFPHYS,
+ UV__EXCLUDE_IFADDR
+};
+
typedef enum {
UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */
UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */
@@ -173,7 +185,8 @@ struct uv__stream_queued_fds_s {
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || \
defined(__linux__) || \
- defined(__OpenBSD__)
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
#define uv__cloexec uv__cloexec_ioctl
#define uv__nonblock uv__nonblock_ioctl
#else
diff --git a/Utilities/cmlibuv/src/unix/kqueue.c b/Utilities/cmlibuv/src/unix/kqueue.c
index 6bc60bb..5e89bdc 100644
--- a/Utilities/cmlibuv/src/unix/kqueue.c
+++ b/Utilities/cmlibuv/src/unix/kqueue.c
@@ -34,6 +34,17 @@
#include <fcntl.h>
#include <time.h>
+/*
+ * Required on
+ * - Until at least FreeBSD 11.0
+ * - Older versions of Mac OS X
+ *
+ * http://www.boost.org/doc/libs/1_61_0/boost/asio/detail/kqueue_reactor.hpp
+ */
+#ifndef EV_OOBAND
+#define EV_OOBAND EV_FLAG1
+#endif
+
static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags);
@@ -48,11 +59,12 @@ int uv__kqueue_init(uv_loop_t* loop) {
}
+#if defined(__APPLE__)
static int uv__has_forked_with_cfrunloop;
+#endif
int uv__io_fork(uv_loop_t* loop) {
int err;
- uv__close(loop->backend_fd);
loop->backend_fd = -1;
err = uv__kqueue_init(loop);
if (err)
@@ -166,6 +178,16 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
}
}
+ if ((w->events & UV__POLLPRI) == 0 && (w->pevents & UV__POLLPRI) != 0) {
+ EV_SET(events + nevents, w->fd, EV_OOBAND, EV_ADD, 0, 0, 0);
+
+ if (++nevents == ARRAY_SIZE(events)) {
+ if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
+ abort();
+ nevents = 0;
+ }
+ }
+
w->events = w->pevents;
}
@@ -275,6 +297,20 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
}
}
+ if (ev->filter == EV_OOBAND) {
+ if (w->pevents & UV__POLLPRI) {
+ revents |= UV__POLLPRI;
+ w->rcount = ev->data;
+ } else {
+ /* TODO batch up */
+ struct kevent events[1];
+ EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
+ if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
+ if (errno != ENOENT)
+ abort();
+ }
+ }
+
if (ev->filter == EVFILT_WRITE) {
if (w->pevents & POLLOUT) {
revents |= POLLOUT;
diff --git a/Utilities/cmlibuv/src/unix/linux-core.c b/Utilities/cmlibuv/src/unix/linux-core.c
index 2866e93..4d480ce 100644
--- a/Utilities/cmlibuv/src/unix/linux-core.c
+++ b/Utilities/cmlibuv/src/unix/linux-core.c
@@ -388,7 +388,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
* free when we switch over to edge-triggered I/O.
*/
if (pe->events == POLLERR || pe->events == POLLHUP)
- pe->events |= w->pevents & (POLLIN | POLLOUT);
+ pe->events |= w->pevents & (POLLIN | POLLOUT | UV__POLLPRI);
if (pe->events != 0) {
/* Run signal watchers last. This also affects child process watchers
@@ -837,7 +837,7 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
uv__free(cpu_infos);
}
-static int uv__ifaddr_exclude(struct ifaddrs *ent) {
+static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
return 1;
if (ent->ifa_addr == NULL)
@@ -847,8 +847,8 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent) {
* devices. We're not interested in this information yet.
*/
if (ent->ifa_addr->sa_family == PF_PACKET)
- return 1;
- return 0;
+ return exclude_type;
+ return !exclude_type;
}
int uv_interface_addresses(uv_interface_address_t** addresses,
@@ -869,7 +869,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
/* Count the number of interfaces */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
- if (uv__ifaddr_exclude(ent))
+ if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
continue;
(*count)++;
@@ -887,7 +887,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
address = *addresses;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
- if (uv__ifaddr_exclude(ent))
+ if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
continue;
address->name = uv__strdup(ent->ifa_name);
@@ -911,7 +911,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
/* Fill in physical addresses for each interface */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
- if (uv__ifaddr_exclude(ent))
+ if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
continue;
address = *addresses;
diff --git a/Utilities/cmlibuv/src/unix/loop.c b/Utilities/cmlibuv/src/unix/loop.c
index bcd4924..5b5b0e0 100644
--- a/Utilities/cmlibuv/src/unix/loop.c
+++ b/Utilities/cmlibuv/src/unix/loop.c
@@ -31,7 +31,6 @@ int uv_loop_init(uv_loop_t* loop) {
void* saved_data;
int err;
- uv__signal_global_once_init();
saved_data = loop->data;
memset(loop, 0, sizeof(*loop));
@@ -68,6 +67,7 @@ int uv_loop_init(uv_loop_t* loop) {
if (err)
return err;
+ uv__signal_global_once_init();
err = uv_signal_init(loop, &loop->child_watcher);
if (err)
goto fail_signal_init;
diff --git a/Utilities/cmlibuv/src/unix/netbsd.c b/Utilities/cmlibuv/src/unix/netbsd.c
index 9b5546b..7425072 100644
--- a/Utilities/cmlibuv/src/unix/netbsd.c
+++ b/Utilities/cmlibuv/src/unix/netbsd.c
@@ -40,9 +40,16 @@
#include <unistd.h>
#include <time.h>
+static uv_mutex_t process_title_mutex;
+static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
static char *process_title;
+static void init_process_title_mutex_once(void) {
+ uv_mutex_init(&process_title_mutex);
+}
+
+
int uv__platform_loop_init(uv_loop_t* loop) {
return uv__kqueue_init(loop);
}
@@ -66,22 +73,32 @@ void uv_loadavg(double avg[3]) {
int uv_exepath(char* buffer, size_t* size) {
+ /* Intermediate buffer, retrieving partial path name does not work
+ * As of NetBSD-8(beta), vnode->path translator does not handle files
+ * with longer names than 31 characters.
+ */
+ char int_buf[PATH_MAX];
+ size_t int_size;
int mib[4];
- size_t cb;
- pid_t mypid;
if (buffer == NULL || size == NULL || *size == 0)
return -EINVAL;
- mypid = getpid();
mib[0] = CTL_KERN;
mib[1] = KERN_PROC_ARGS;
- mib[2] = mypid;
- mib[3] = KERN_PROC_ARGV;
+ mib[2] = -1;
+ mib[3] = KERN_PROC_PATHNAME;
+ int_size = ARRAY_SIZE(int_buf);
- cb = *size;
- if (sysctl(mib, 4, buffer, &cb, NULL, 0))
+ if (sysctl(mib, 4, int_buf, &int_size, NULL, 0))
return -errno;
+
+ /* Copy string from the intermediate buffer to outer one with appropriate
+ * length.
+ */
+ strlcpy(buffer, int_buf, *size);
+
+ /* Set new size. */
*size = strlen(buffer);
return 0;
@@ -124,11 +141,24 @@ char** uv_setup_args(int argc, char** argv) {
int uv_set_process_title(const char* title) {
- if (process_title) uv__free(process_title);
+ char* new_title;
+
+ new_title = uv__strdup(title);
+
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
- process_title = uv__strdup(title);
+ if (process_title == NULL) {
+ uv_mutex_unlock(&process_title_mutex);
+ return -ENOMEM;
+ }
+
+ uv__free(process_title);
+ process_title = new_title;
setproctitle("%s", title);
+ uv_mutex_unlock(&process_title_mutex);
+
return 0;
}
@@ -139,17 +169,24 @@ int uv_get_process_title(char* buffer, size_t size) {
if (buffer == NULL || size == 0)
return -EINVAL;
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
if (process_title) {
len = strlen(process_title) + 1;
- if (size < len)
+ if (size < len) {
+ uv_mutex_unlock(&process_title_mutex);
return -ENOBUFS;
+ }
memcpy(buffer, process_title, len);
} else {
len = 0;
}
+ uv_mutex_unlock(&process_title_mutex);
+
buffer[len] = '\0';
return 0;
diff --git a/Utilities/cmlibuv/src/unix/openbsd.c b/Utilities/cmlibuv/src/unix/openbsd.c
index 56f0af1..c0ffa56 100644
--- a/Utilities/cmlibuv/src/unix/openbsd.c
+++ b/Utilities/cmlibuv/src/unix/openbsd.c
@@ -36,9 +36,16 @@
#include <unistd.h>
+static uv_mutex_t process_title_mutex;
+static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
static char *process_title;
+static void init_process_title_mutex_once(void) {
+ uv_mutex_init(&process_title_mutex);
+}
+
+
int uv__platform_loop_init(uv_loop_t* loop) {
return uv__kqueue_init(loop);
}
@@ -146,9 +153,24 @@ char** uv_setup_args(int argc, char** argv) {
int uv_set_process_title(const char* title) {
+ char* new_title;
+
+ new_title = uv__strdup(title);
+
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
+ if (process_title == NULL) {
+ uv_mutex_unlock(&process_title_mutex);
+ return -ENOMEM;
+ }
+
uv__free(process_title);
- process_title = uv__strdup(title);
+ process_title = new_title;
setproctitle("%s", title);
+
+ uv_mutex_unlock(&process_title_mutex);
+
return 0;
}
@@ -159,17 +181,24 @@ int uv_get_process_title(char* buffer, size_t size) {
if (buffer == NULL || size == 0)
return -EINVAL;
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
if (process_title) {
len = strlen(process_title) + 1;
- if (size < len)
+ if (size < len) {
+ uv_mutex_unlock(&process_title_mutex);
return -ENOBUFS;
+ }
memcpy(buffer, process_title, len);
} else {
len = 0;
}
+ uv_mutex_unlock(&process_title_mutex);
+
buffer[len] = '\0';
return 0;
diff --git a/Utilities/cmlibuv/src/unix/os390-syscalls.c b/Utilities/cmlibuv/src/unix/os390-syscalls.c
index 7edf235..21558ea 100644
--- a/Utilities/cmlibuv/src/unix/os390-syscalls.c
+++ b/Utilities/cmlibuv/src/unix/os390-syscalls.c
@@ -25,6 +25,8 @@
#include <stdlib.h>
#include <assert.h>
#include <search.h>
+#include <termios.h>
+#include <sys/msg.h>
#define CW_CONDVAR 32
@@ -103,10 +105,19 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
unsigned int newsize;
unsigned int i;
struct pollfd* newlst;
+ struct pollfd event;
if (len <= lst->size)
return;
+ if (lst->size == 0)
+ event.fd = -1;
+ else {
+ /* Extract the message queue at the end. */
+ event = lst->items[lst->size - 1];
+ lst->items[lst->size - 1].fd = -1;
+ }
+
newsize = next_power_of_two(len);
newlst = uv__realloc(lst->items, newsize * sizeof(lst->items[0]));
@@ -115,32 +126,101 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
for (i = lst->size; i < newsize; ++i)
newlst[i].fd = -1;
+ /* Restore the message queue at the end */
+ newlst[newsize - 1] = event;
+
lst->items = newlst;
lst->size = newsize;
}
+static void init_message_queue(uv__os390_epoll* lst) {
+ struct {
+ long int header;
+ char body;
+ } msg;
+
+ /* initialize message queue */
+ lst->msg_queue = msgget(IPC_PRIVATE, 0622 | IPC_CREAT);
+ if (lst->msg_queue == -1)
+ abort();
+
+ /*
+ On z/OS, the message queue will be affiliated with the process only
+ when a send is performed on it. Once this is done, the system
+ can be queried for all message queues belonging to our process id.
+ */
+ msg.header = 1;
+ if (msgsnd(lst->msg_queue, &msg, sizeof(msg.body), 0) != 0)
+ abort();
+
+ /* Clean up the dummy message sent above */
+ if (msgrcv(lst->msg_queue, &msg, sizeof(msg.body), 0, 0) != sizeof(msg.body))
+ abort();
+}
+
+
+static void before_fork(void) {
+ uv_mutex_lock(&global_epoll_lock);
+}
+
+
+static void after_fork(void) {
+ uv_mutex_unlock(&global_epoll_lock);
+}
+
+
+static void child_fork(void) {
+ QUEUE* q;
+ uv_once_t child_once = UV_ONCE_INIT;
+
+ /* reset once */
+ memcpy(&once, &child_once, sizeof(child_once));
+
+ /* reset epoll list */
+ while (!QUEUE_EMPTY(&global_epoll_queue)) {
+ uv__os390_epoll* lst;
+ q = QUEUE_HEAD(&global_epoll_queue);
+ QUEUE_REMOVE(q);
+ lst = QUEUE_DATA(q, uv__os390_epoll, member);
+ uv__free(lst->items);
+ lst->items = NULL;
+ lst->size = 0;
+ }
+
+ uv_mutex_unlock(&global_epoll_lock);
+ uv_mutex_destroy(&global_epoll_lock);
+}
+
+
static void epoll_init(void) {
QUEUE_INIT(&global_epoll_queue);
if (uv_mutex_init(&global_epoll_lock))
abort();
+
+ if (pthread_atfork(&before_fork, &after_fork, &child_fork))
+ abort();
}
uv__os390_epoll* epoll_create1(int flags) {
uv__os390_epoll* lst;
- uv_once(&once, epoll_init);
- uv_mutex_lock(&global_epoll_lock);
lst = uv__malloc(sizeof(*lst));
- if (lst == -1)
- return NULL;
- QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member);
- uv_mutex_unlock(&global_epoll_lock);
+ if (lst != NULL) {
+ /* initialize list */
+ lst->size = 0;
+ lst->items = NULL;
+ init_message_queue(lst);
+ maybe_resize(lst, 1);
+ lst->items[lst->size - 1].fd = lst->msg_queue;
+ lst->items[lst->size - 1].events = POLLIN;
+ uv_once(&once, epoll_init);
+ uv_mutex_lock(&global_epoll_lock);
+ QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member);
+ uv_mutex_unlock(&global_epoll_lock);
+ }
- /* initialize list */
- lst->size = 0;
- lst->items = NULL;
return lst;
}
@@ -149,22 +229,32 @@ int epoll_ctl(uv__os390_epoll* lst,
int op,
int fd,
struct epoll_event *event) {
- if(op == EPOLL_CTL_DEL) {
+ uv_mutex_lock(&global_epoll_lock);
+
+ if (op == EPOLL_CTL_DEL) {
if (fd >= lst->size || lst->items[fd].fd == -1) {
+ uv_mutex_unlock(&global_epoll_lock);
errno = ENOENT;
return -1;
}
lst->items[fd].fd = -1;
- } else if(op == EPOLL_CTL_ADD) {
- maybe_resize(lst, fd + 1);
+ } else if (op == EPOLL_CTL_ADD) {
+
+ /* Resizing to 'fd + 1' would expand the list to contain at least
+ * 'fd'. But we need to guarantee that the last index on the list
+ * is reserved for the message queue. So specify 'fd + 2' instead.
+ */
+ maybe_resize(lst, fd + 2);
if (lst->items[fd].fd != -1) {
+ uv_mutex_unlock(&global_epoll_lock);
errno = EEXIST;
return -1;
}
lst->items[fd].fd = fd;
lst->items[fd].events = event->events;
- } else if(op == EPOLL_CTL_MOD) {
+ } else if (op == EPOLL_CTL_MOD) {
if (fd >= lst->size || lst->items[fd].fd == -1) {
+ uv_mutex_unlock(&global_epoll_lock);
errno = ENOENT;
return -1;
}
@@ -172,44 +262,36 @@ int epoll_ctl(uv__os390_epoll* lst,
} else
abort();
+ uv_mutex_unlock(&global_epoll_lock);
return 0;
}
int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
int maxevents, int timeout) {
- size_t size;
+ nmsgsfds_t size;
struct pollfd* pfds;
int pollret;
int reventcount;
- uv_mutex_lock(&global_epoll_lock);
- uv_mutex_unlock(&global_epoll_lock);
- size = lst->size;
+ size = _SET_FDS_MSGS(size, 1, lst->size - 1);
pfds = lst->items;
pollret = poll(pfds, size, timeout);
- if(pollret == -1)
+ if (pollret <= 0)
return pollret;
+ pollret = _NFDS(pollret) + _NMSGS(pollret);
+
reventcount = 0;
- for (int i = 0; i < lst->size && i < maxevents; ++i) {
+ for (int i = 0;
+ i < lst->size && i < maxevents && reventcount < pollret; ++i) {
struct epoll_event ev;
- ev.events = 0;
- ev.fd = pfds[i].fd;
- if(!pfds[i].revents)
+ if (pfds[i].fd == -1 || pfds[i].revents == 0)
continue;
- if(pfds[i].revents & POLLRDNORM)
- ev.events = ev.events | POLLIN;
-
- if(pfds[i].revents & POLLWRNORM)
- ev.events = ev.events | POLLOUT;
-
- if(pfds[i].revents & POLLHUP)
- ev.events = ev.events | POLLHUP;
-
- pfds[i].revents = 0;
+ ev.fd = pfds[i].fd;
+ ev.events = pfds[i].revents;
events[reventcount++] = ev;
}
@@ -235,9 +317,14 @@ int epoll_file_close(int fd) {
}
void epoll_queue_close(uv__os390_epoll* lst) {
+ /* Remove epoll instance from global queue */
uv_mutex_lock(&global_epoll_lock);
QUEUE_REMOVE(&lst->member);
uv_mutex_unlock(&global_epoll_lock);
+
+ /* Free resources */
+ msgctl(lst->msg_queue, IPC_RMID, NULL);
+ lst->msg_queue = -1;
uv__free(lst->items);
lst->items = NULL;
}
@@ -332,3 +419,81 @@ char* mkdtemp(char* path) {
return path;
}
+
+
+ssize_t os390_readlink(const char* path, char* buf, size_t len) {
+ ssize_t rlen;
+ ssize_t vlen;
+ ssize_t plen;
+ char* delimiter;
+ char old_delim;
+ char* tmpbuf;
+ char realpathstr[PATH_MAX + 1];
+
+ tmpbuf = uv__malloc(len + 1);
+ if (tmpbuf == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ rlen = readlink(path, tmpbuf, len);
+ if (rlen < 0) {
+ uv__free(tmpbuf);
+ return rlen;
+ }
+
+ if (rlen < 3 || strncmp("/$", tmpbuf, 2) != 0) {
+ /* Straightforward readlink. */
+ memcpy(buf, tmpbuf, rlen);
+ uv__free(tmpbuf);
+ return rlen;
+ }
+
+ /*
+ * There is a parmlib variable at the beginning
+ * which needs interpretation.
+ */
+ tmpbuf[rlen] = '\0';
+ delimiter = strchr(tmpbuf + 2, '/');
+ if (delimiter == NULL)
+ /* No slash at the end */
+ delimiter = strchr(tmpbuf + 2, '\0');
+
+ /* Read real path of the variable. */
+ old_delim = *delimiter;
+ *delimiter = '\0';
+ if (realpath(tmpbuf, realpathstr) == NULL) {
+ uv__free(tmpbuf);
+ return -1;
+ }
+
+ /* realpathstr is not guaranteed to end with null byte.*/
+ realpathstr[PATH_MAX] = '\0';
+
+ /* Reset the delimiter and fill up the buffer. */
+ *delimiter = old_delim;
+ plen = strlen(delimiter);
+ vlen = strlen(realpathstr);
+ rlen = plen + vlen;
+ if (rlen > len) {
+ uv__free(tmpbuf);
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ memcpy(buf, realpathstr, vlen);
+ memcpy(buf + vlen, delimiter, plen);
+
+ /* Done using temporary buffer. */
+ uv__free(tmpbuf);
+
+ return rlen;
+}
+
+
+size_t strnlen(const char* str, size_t maxlen) {
+ void* p = memchr(str, 0, maxlen);
+ if (p == NULL)
+ return maxlen;
+ else
+ return p - str;
+}
diff --git a/Utilities/cmlibuv/src/unix/os390-syscalls.h b/Utilities/cmlibuv/src/unix/os390-syscalls.h
index 61a7cee..6e34a88 100644
--- a/Utilities/cmlibuv/src/unix/os390-syscalls.h
+++ b/Utilities/cmlibuv/src/unix/os390-syscalls.h
@@ -50,6 +50,7 @@ typedef struct {
QUEUE member;
struct pollfd* items;
unsigned long size;
+ int msg_queue;
} uv__os390_epoll;
/* epoll api */
@@ -65,5 +66,7 @@ int scandir(const char* maindir, struct dirent*** namelist,
int (*compar)(const struct dirent **,
const struct dirent **));
char *mkdtemp(char* path);
+ssize_t os390_readlink(const char* path, char* buf, size_t len);
+size_t strnlen(const char* str, size_t maxlen);
#endif /* UV_OS390_SYSCALL_H_ */
diff --git a/Utilities/cmlibuv/src/unix/os390.c b/Utilities/cmlibuv/src/unix/os390.c
index 2ba5abf..081438e 100644
--- a/Utilities/cmlibuv/src/unix/os390.c
+++ b/Utilities/cmlibuv/src/unix/os390.c
@@ -25,6 +25,9 @@
#include <utmpx.h>
#include <unistd.h>
#include <sys/ps.h>
+#include <builtins.h>
+#include <termios.h>
+#include <sys/msg.h>
#if defined(__clang__)
#include "csrsic.h"
#else
@@ -32,6 +35,7 @@
#endif
#define CVT_PTR 0x10
+#define PSA_PTR 0x00
#define CSD_OFFSET 0x294
/*
@@ -69,6 +73,18 @@
/* CPC model length from the CSRSI Service. */
#define CPCMODEL_LENGTH 16
+/* Pointer to the home (current) ASCB. */
+#define PSAAOLD 0x224
+
+/* Pointer to rsm address space block extension. */
+#define ASCBRSME 0x16C
+
+/*
+ NUMBER OF FRAMES CURRENTLY IN USE BY THIS ADDRESS SPACE.
+ It does not include 2G frames.
+*/
+#define RAXFMCT 0x2C
+
/* Thread Entry constants */
#define PGTH_CURRENT 1
#define PGTH_LEN 26
@@ -76,6 +92,9 @@
#pragma linkage(BPX4GTH, OS)
#pragma linkage(BPX1GTH, OS)
+/* TOD Clock resolution in nanoseconds */
+#define TOD_RES 4.096
+
typedef unsigned data_area_ptr_assign_type;
typedef union {
@@ -100,7 +119,7 @@ void uv_loadavg(double avg[3]) {
int uv__platform_loop_init(uv_loop_t* loop) {
uv__os390_epoll* ep;
- ep = epoll_create1(UV__EPOLL_CLOEXEC);
+ ep = epoll_create1(0);
loop->ep = ep;
if (ep == NULL)
return -errno;
@@ -118,9 +137,10 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
uint64_t uv__hrtime(uv_clocktype_t type) {
- struct timeval time;
- gettimeofday(&time, NULL);
- return (uint64_t) time.tv_sec * 1e9 + time.tv_usec * 1e3;
+ unsigned long long timestamp;
+ __stckf(&timestamp);
+ /* Convert to nanoseconds */
+ return timestamp / TOD_RES;
}
@@ -337,13 +357,17 @@ uint64_t uv_get_total_memory(void) {
int uv_resident_set_memory(size_t* rss) {
- W_PSPROC buf;
+ char* psa;
+ char* ascb;
+ char* rax;
+ size_t nframes;
- memset(&buf, 0, sizeof(buf));
- if (w_getpsent(0, &buf, sizeof(W_PSPROC)) == -1)
- return -EINVAL;
+ psa = PSA_PTR;
+ ascb = *(char* __ptr32 *)(psa + PSAAOLD);
+ rax = *(char* __ptr32 *)(ascb + ASCBRSME);
+ nframes = *(unsigned int*)(rax + RAXFMCT);
- *rss = buf.ps_size;
+ *rss = nframes * sysconf(_SC_PAGESIZE);
return 0;
}
@@ -364,7 +388,6 @@ int uv_uptime(double* uptime) {
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
uv_cpu_info_t* cpu_info;
- int result;
int idx;
siv1v2 info;
data_area_ptr cvt = {0};
@@ -663,11 +686,124 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) {
return 0;
}
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+ uv_fs_event_stop(handle);
+}
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
+ return 0;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
+ const char* filename, unsigned int flags) {
+ uv__os390_epoll* ep;
+ _RFIS reg_struct;
+ char* path;
+ int rc;
+
+ if (uv__is_active(handle))
+ return -EINVAL;
+
+ ep = handle->loop->ep;
+ assert(ep->msg_queue != -1);
+
+ reg_struct.__rfis_cmd = _RFIS_REG;
+ reg_struct.__rfis_qid = ep->msg_queue;
+ reg_struct.__rfis_type = 1;
+ memcpy(reg_struct.__rfis_utok, &handle, sizeof(handle));
+
+ path = uv__strdup(filename);
+ if (path == NULL)
+ return -ENOMEM;
+
+ rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), &reg_struct);
+ if (rc != 0)
+ return -errno;
+
+ uv__handle_start(handle);
+ handle->path = path;
+ handle->cb = cb;
+ memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok,
+ sizeof(handle->rfis_rftok));
+
+ return 0;
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ uv__os390_epoll* ep;
+ _RFIS reg_struct;
+ int rc;
+
+ if (!uv__is_active(handle))
+ return 0;
+
+ ep = handle->loop->ep;
+ assert(ep->msg_queue != -1);
+
+ reg_struct.__rfis_cmd = _RFIS_UNREG;
+ reg_struct.__rfis_qid = ep->msg_queue;
+ reg_struct.__rfis_type = 1;
+ memcpy(reg_struct.__rfis_rftok, handle->rfis_rftok,
+ sizeof(handle->rfis_rftok));
+
+ /*
+ * This call will take "/" as the path argument in case we
+ * don't care to supply the correct path. The system will simply
+ * ignore it.
+ */
+ rc = __w_pioctl("/", _IOCC_REGFILEINT, sizeof(reg_struct), &reg_struct);
+ if (rc != 0 && errno != EALREADY && errno != ENOENT)
+ abort();
+
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+
+static int os390_message_queue_handler(uv__os390_epoll* ep) {
+ uv_fs_event_t* handle;
+ int msglen;
+ int events;
+ _RFIM msg;
+
+ if (ep->msg_queue == -1)
+ return 0;
+
+ msglen = msgrcv(ep->msg_queue, &msg, sizeof(msg), 0, IPC_NOWAIT);
+
+ if (msglen == -1 && errno == ENOMSG)
+ return 0;
+
+ if (msglen == -1)
+ abort();
+
+ events = 0;
+ if (msg.__rfim_event == _RFIM_ATTR || msg.__rfim_event == _RFIM_WRITE)
+ events = UV_CHANGE;
+ else if (msg.__rfim_event == _RFIM_RENAME)
+ events = UV_RENAME;
+ else
+ /* Some event that we are not interested in. */
+ return 0;
+
+ handle = *(uv_fs_event_t**)(msg.__rfim_utok);
+ handle->cb(handle, uv__basename_r(handle->path), events, 0);
+ return 1;
+}
+
+
void uv__io_poll(uv_loop_t* loop, int timeout) {
static const int max_safe_timeout = 1789569;
struct epoll_event events[1024];
struct epoll_event* pe;
struct epoll_event e;
+ uv__os390_epoll* ep;
int real_timeout;
QUEUE* q;
uv__io_t* w;
@@ -745,9 +881,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
SAVE_ERRNO(uv__update_time(loop));
if (nfds == 0) {
assert(timeout != -1);
- timeout = real_timeout - timeout;
- if (timeout > 0)
+
+ if (timeout > 0) {
+ timeout = real_timeout - timeout;
continue;
+ }
return;
}
@@ -779,6 +917,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (fd == -1)
continue;
+ ep = loop->ep;
+ if (fd == ep->msg_queue) {
+ os390_message_queue_handler(ep);
+ continue;
+ }
+
assert(fd >= 0);
assert((unsigned) fd < loop->nwatchers);
@@ -843,7 +987,12 @@ void uv__set_process_title(const char* title) {
}
int uv__io_fork(uv_loop_t* loop) {
- uv__platform_loop_delete(loop);
+ /*
+ Nullify the msg queue but don't close it because
+ it is still being used by the parent.
+ */
+ loop->ep = NULL;
+ uv__platform_loop_delete(loop);
return uv__platform_loop_init(loop);
}
diff --git a/Utilities/cmlibuv/src/unix/pipe.c b/Utilities/cmlibuv/src/unix/pipe.c
index e3d436d..df3aad0 100644
--- a/Utilities/cmlibuv/src/unix/pipe.c
+++ b/Utilities/cmlibuv/src/unix/pipe.c
@@ -300,3 +300,56 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
else
return uv__handle_type(handle->accepted_fd);
}
+
+
+int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
+ unsigned desired_mode;
+ struct stat pipe_stat;
+ char* name_buffer;
+ size_t name_len;
+ int r;
+
+ if (handle == NULL || uv__stream_fd(handle) == -1)
+ return -EBADF;
+
+ if (mode != UV_READABLE &&
+ mode != UV_WRITABLE &&
+ mode != (UV_WRITABLE | UV_READABLE))
+ return -EINVAL;
+
+ if (fstat(uv__stream_fd(handle), &pipe_stat) == -1)
+ return -errno;
+
+ desired_mode = 0;
+ if (mode & UV_READABLE)
+ desired_mode |= S_IRUSR | S_IRGRP | S_IROTH;
+ if (mode & UV_WRITABLE)
+ desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
+
+ /* Exit early if pipe already has desired mode. */
+ if ((pipe_stat.st_mode & desired_mode) == desired_mode)
+ return 0;
+
+ pipe_stat.st_mode |= desired_mode;
+
+ /* Unfortunately fchmod does not work on all platforms, we will use chmod. */
+ name_len = 0;
+ r = uv_pipe_getsockname(handle, NULL, &name_len);
+ if (r != UV_ENOBUFS)
+ return r;
+
+ name_buffer = uv__malloc(name_len);
+ if (name_buffer == NULL)
+ return UV_ENOMEM;
+
+ r = uv_pipe_getsockname(handle, name_buffer, &name_len);
+ if (r != 0) {
+ uv__free(name_buffer);
+ return r;
+ }
+
+ r = chmod(name_buffer, pipe_stat.st_mode);
+ uv__free(name_buffer);
+
+ return r != -1 ? 0 : -errno;
+}
diff --git a/Utilities/cmlibuv/src/unix/poll.c b/Utilities/cmlibuv/src/unix/poll.c
index 370994b..816c7dc 100644
--- a/Utilities/cmlibuv/src/unix/poll.c
+++ b/Utilities/cmlibuv/src/unix/poll.c
@@ -33,8 +33,19 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
handle = container_of(w, uv_poll_t, io_watcher);
- if (events & POLLERR) {
- uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP);
+ /*
+ * As documented in the kernel source fs/kernfs/file.c #780
+ * poll will return POLLERR|POLLPRI in case of sysfs
+ * polling. This does not happen in case of out-of-band
+ * TCP messages.
+ *
+ * The above is the case on (at least) FreeBSD and Linux.
+ *
+ * So to properly determine a POLLPRI or a POLLERR we need
+ * to check for both.
+ */
+ if ((events & POLLERR) && !(events & UV__POLLPRI)) {
+ uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
uv__handle_stop(handle);
handle->poll_cb(handle, -EBADF, 0);
return;
@@ -43,6 +54,8 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
pevents = 0;
if (events & POLLIN)
pevents |= UV_READABLE;
+ if (events & UV__POLLPRI)
+ pevents |= UV_PRIORITIZED;
if (events & POLLOUT)
pevents |= UV_WRITABLE;
if (events & UV__POLLRDHUP)
@@ -86,8 +99,9 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
static void uv__poll_stop(uv_poll_t* handle) {
uv__io_stop(handle->loop,
&handle->io_watcher,
- POLLIN | POLLOUT | UV__POLLRDHUP);
+ POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
uv__handle_stop(handle);
+ uv__platform_invalidate_fd(handle->loop, handle->io_watcher.fd);
}
@@ -101,7 +115,8 @@ int uv_poll_stop(uv_poll_t* handle) {
int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
int events;
- assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
+ assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT |
+ UV_PRIORITIZED)) == 0);
assert(!uv__is_closing(handle));
uv__poll_stop(handle);
@@ -112,6 +127,8 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
events = 0;
if (pevents & UV_READABLE)
events |= POLLIN;
+ if (pevents & UV_PRIORITIZED)
+ events |= UV__POLLPRI;
if (pevents & UV_WRITABLE)
events |= POLLOUT;
if (pevents & UV_DISCONNECT)
diff --git a/Utilities/cmlibuv/src/unix/process.c b/Utilities/cmlibuv/src/unix/process.c
index f2fe305..9842710 100644
--- a/Utilities/cmlibuv/src/unix/process.c
+++ b/Utilities/cmlibuv/src/unix/process.c
@@ -279,9 +279,12 @@ static void uv__process_child_init(const uv_process_options_t* options,
int stdio_count,
int (*pipes)[2],
int error_fd) {
+ sigset_t set;
int close_fd;
int use_fd;
+ int err;
int fd;
+ int n;
if (options->flags & UV_PROCESS_DETACHED)
setsid();
@@ -376,6 +379,31 @@ static void uv__process_child_init(const uv_process_options_t* options,
environ = options->env;
}
+ /* Reset signal disposition. Use a hard-coded limit because NSIG
+ * is not fixed on Linux: it's either 32, 34 or 64, depending on
+ * whether RT signals are enabled. We are not allowed to touch
+ * RT signal handlers, glibc uses them internally.
+ */
+ for (n = 1; n < 32; n += 1) {
+ if (n == SIGKILL || n == SIGSTOP)
+ continue; /* Can't be changed. */
+
+ if (SIG_ERR != signal(n, SIG_DFL))
+ continue;
+
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+
+ /* Reset signal mask. */
+ sigemptyset(&set);
+ err = pthread_sigmask(SIG_SETMASK, &set, NULL);
+
+ if (err != 0) {
+ uv__write_int(error_fd, -err);
+ _exit(127);
+ }
+
execvp(options->file, options->args);
uv__write_int(error_fd, -errno);
_exit(127);
@@ -391,6 +419,7 @@ int uv_spawn(uv_loop_t* loop,
return -ENOSYS;
#else
int signal_pipe[2] = { -1, -1 };
+ int pipes_storage[8][2];
int (*pipes)[2];
int stdio_count;
ssize_t r;
@@ -415,7 +444,10 @@ int uv_spawn(uv_loop_t* loop,
stdio_count = 3;
err = -ENOMEM;
- pipes = uv__malloc(stdio_count * sizeof(*pipes));
+ pipes = pipes_storage;
+ if (stdio_count > (int) ARRAY_SIZE(pipes_storage))
+ pipes = uv__malloc(stdio_count * sizeof(*pipes));
+
if (pipes == NULL)
goto error;
@@ -520,7 +552,9 @@ int uv_spawn(uv_loop_t* loop,
process->pid = pid;
process->exit_cb = options->exit_cb;
- uv__free(pipes);
+ if (pipes != pipes_storage)
+ uv__free(pipes);
+
return exec_errorno;
error:
@@ -534,7 +568,9 @@ error:
if (pipes[i][1] != -1)
uv__close_nocheckstdio(pipes[i][1]);
}
- uv__free(pipes);
+
+ if (pipes != pipes_storage)
+ uv__free(pipes);
}
return err;
diff --git a/Utilities/cmlibuv/src/unix/proctitle.c b/Utilities/cmlibuv/src/unix/proctitle.c
index 9160f7e..1b3a798 100644
--- a/Utilities/cmlibuv/src/unix/proctitle.c
+++ b/Utilities/cmlibuv/src/unix/proctitle.c
@@ -26,6 +26,8 @@
extern void uv__set_process_title(const char* title);
+static uv_mutex_t process_title_mutex;
+static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
static void* args_mem;
static struct {
@@ -34,6 +36,11 @@ static struct {
} process_title;
+static void init_process_title_mutex_once(void) {
+ uv_mutex_init(&process_title_mutex);
+}
+
+
char** uv_setup_args(int argc, char** argv) {
char** new_argv;
size_t size;
@@ -81,12 +88,16 @@ char** uv_setup_args(int argc, char** argv) {
int uv_set_process_title(const char* title) {
- if (process_title.len == 0)
- return 0;
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
+ if (process_title.len != 0) {
+ /* No need to terminate, byte after is always '\0'. */
+ strncpy(process_title.str, title, process_title.len);
+ uv__set_process_title(title);
+ }
- /* No need to terminate, byte after is always '\0'. */
- strncpy(process_title.str, title, process_title.len);
- uv__set_process_title(title);
+ uv_mutex_unlock(&process_title_mutex);
return 0;
}
@@ -95,12 +106,22 @@ int uv_set_process_title(const char* title) {
int uv_get_process_title(char* buffer, size_t size) {
if (buffer == NULL || size == 0)
return -EINVAL;
- else if (size <= process_title.len)
+
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
+ if (size <= process_title.len) {
+ uv_mutex_unlock(&process_title_mutex);
return -ENOBUFS;
+ }
+
+ if (process_title.len != 0)
+ memcpy(buffer, process_title.str, process_title.len + 1);
- memcpy(buffer, process_title.str, process_title.len + 1);
buffer[process_title.len] = '\0';
+ uv_mutex_unlock(&process_title_mutex);
+
return 0;
}
diff --git a/Utilities/cmlibuv/src/unix/pthread-barrier.c b/Utilities/cmlibuv/src/unix/pthread-barrier.c
deleted file mode 100644
index b6e604d..0000000
--- a/Utilities/cmlibuv/src/unix/pthread-barrier.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
-Copyright (c) 2016, Kari Tristan Helgason <kthelgason@gmail.com>
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-#include "uv-common.h"
-#include "pthread-barrier.h"
-
-#include <stdlib.h>
-#include <assert.h>
-
-/* TODO: support barrier_attr */
-int pthread_barrier_init(pthread_barrier_t* barrier,
- const void* barrier_attr,
- unsigned count) {
- int rc;
- _uv_barrier* b;
-
- if (barrier == NULL || count == 0)
- return EINVAL;
-
- if (barrier_attr != NULL)
- return ENOTSUP;
-
- b = uv__malloc(sizeof(*b));
- if (b == NULL)
- return ENOMEM;
-
- b->in = 0;
- b->out = 0;
- b->threshold = count;
-
- if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0)
- goto error2;
- if ((rc = pthread_cond_init(&b->cond, NULL)) != 0)
- goto error;
-
- barrier->b = b;
- return 0;
-
-error:
- pthread_mutex_destroy(&b->mutex);
-error2:
- uv__free(b);
- return rc;
-}
-
-int pthread_barrier_wait(pthread_barrier_t* barrier) {
- int rc;
- _uv_barrier* b;
-
- if (barrier == NULL || barrier->b == NULL)
- return EINVAL;
-
- b = barrier->b;
- /* Lock the mutex*/
- if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
- return rc;
-
- /* Increment the count. If this is the first thread to reach the threshold,
- wake up waiters, unlock the mutex, then return
- PTHREAD_BARRIER_SERIAL_THREAD. */
- if (++b->in == b->threshold) {
- b->in = 0;
- b->out = b->threshold - 1;
- rc = pthread_cond_signal(&b->cond);
- assert(rc == 0);
-
- pthread_mutex_unlock(&b->mutex);
- return PTHREAD_BARRIER_SERIAL_THREAD;
- }
- /* Otherwise, wait for other threads until in is set to 0,
- then return 0 to indicate this is not the first thread. */
- do {
- if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0)
- break;
- } while (b->in != 0);
-
- /* mark thread exit */
- b->out--;
- pthread_cond_signal(&b->cond);
- pthread_mutex_unlock(&b->mutex);
- return rc;
-}
-
-int pthread_barrier_destroy(pthread_barrier_t* barrier) {
- int rc;
- _uv_barrier* b;
-
- if (barrier == NULL || barrier->b == NULL)
- return EINVAL;
-
- b = barrier->b;
-
- if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
- return rc;
-
- if (b->in > 0 || b->out > 0)
- rc = EBUSY;
-
- pthread_mutex_unlock(&b->mutex);
-
- if (rc)
- return rc;
-
- pthread_cond_destroy(&b->cond);
- pthread_mutex_destroy(&b->mutex);
- uv__free(barrier->b);
- barrier->b = NULL;
- return 0;
-}
diff --git a/Utilities/cmlibuv/src/unix/stream.c b/Utilities/cmlibuv/src/unix/stream.c
index 3857bc8..931e5f1 100644
--- a/Utilities/cmlibuv/src/unix/stream.c
+++ b/Utilities/cmlibuv/src/unix/stream.c
@@ -514,7 +514,7 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
int err;
stream = container_of(w, uv_stream_t, io_watcher);
- assert(events == POLLIN);
+ assert(events & POLLIN);
assert(stream->accepted_fd == -1);
assert(!(stream->flags & UV_CLOSING));
@@ -750,6 +750,7 @@ static void uv__write(uv_stream_t* stream) {
int iovmax;
int iovcnt;
ssize_t n;
+ int err;
start:
@@ -782,14 +783,21 @@ start:
*/
if (req->send_handle) {
+ int fd_to_send;
struct msghdr msg;
struct cmsghdr *cmsg;
- int fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle);
union {
char data[64];
struct cmsghdr alias;
} scratch;
+ if (uv__is_closing(req->send_handle)) {
+ err = -EBADF;
+ goto error;
+ }
+
+ fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle);
+
memset(&scratch, 0, sizeof(scratch));
assert(fd_to_send >= 0);
@@ -851,15 +859,9 @@ start:
}
if (n < 0) {
- if (errno != EAGAIN && errno != EWOULDBLOCK) {
- /* Error */
- req->error = -errno;
- uv__write_req_finish(req);
- uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
- if (!uv__io_active(&stream->io_watcher, POLLIN))
- uv__handle_stop(stream);
- uv__stream_osx_interrupt_select(stream);
- return;
+ if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENOBUFS) {
+ err = -errno;
+ goto error;
} else if (stream->flags & UV_STREAM_BLOCKING) {
/* If this is a blocking stream, try again. */
goto start;
@@ -923,6 +925,16 @@ start:
/* Notify select() thread about state change */
uv__stream_osx_interrupt_select(stream);
+
+ return;
+
+error:
+ req->error = err;
+ uv__write_req_finish(req);
+ uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
+ if (!uv__io_active(&stream->io_watcher, POLLIN))
+ uv__handle_stop(stream);
+ uv__stream_osx_interrupt_select(stream);
}
@@ -1249,8 +1261,9 @@ static void uv__read(uv_stream_t* stream) {
int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
- assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE) &&
- "uv_shutdown (unix) only supports uv_handle_t right now");
+ assert(stream->type == UV_TCP ||
+ stream->type == UV_TTY ||
+ stream->type == UV_NAMED_PIPE);
if (!(stream->flags & UV_STREAM_WRITABLE) ||
stream->flags & UV_STREAM_SHUT ||
diff --git a/Utilities/cmlibuv/src/unix/sunos.c b/Utilities/cmlibuv/src/unix/sunos.c
index 041f3f3..d6f9527 100644
--- a/Utilities/cmlibuv/src/unix/sunos.c
+++ b/Utilities/cmlibuv/src/unix/sunos.c
@@ -751,7 +751,8 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent) {
return 1;
if (ent->ifa_addr == NULL)
return 1;
- if (ent->ifa_addr->sa_family == PF_PACKET)
+ if (ent->ifa_addr->sa_family != AF_INET &&
+ ent->ifa_addr->sa_family != AF_INET6)
return 1;
return 0;
}
@@ -760,7 +761,6 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
uv_interface_address_t* address;
struct ifaddrs* addrs;
struct ifaddrs* ent;
- int i;
if (getifaddrs(&addrs))
return -errno;
diff --git a/Utilities/cmlibuv/src/unix/tcp.c b/Utilities/cmlibuv/src/unix/tcp.c
index c423dcb..c7c8d21 100644
--- a/Utilities/cmlibuv/src/unix/tcp.c
+++ b/Utilities/cmlibuv/src/unix/tcp.c
@@ -28,15 +28,12 @@
#include <errno.h>
-static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
+static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
+ struct sockaddr_storage saddr;
+ socklen_t slen;
int sockfd;
int err;
- if (domain == AF_UNSPEC || uv__stream_fd(handle) != -1) {
- handle->flags |= flags;
- return 0;
- }
-
err = uv__socket(domain, SOCK_STREAM, 0);
if (err < 0)
return err;
@@ -48,10 +45,74 @@ static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
return err;
}
+ if (flags & UV_HANDLE_BOUND) {
+ /* Bind this new socket to an arbitrary port */
+ slen = sizeof(saddr);
+ memset(&saddr, 0, sizeof(saddr));
+ err = getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen);
+ if (err) {
+ uv__close(sockfd);
+ return err;
+ }
+
+ err = bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen);
+ if (err) {
+ uv__close(sockfd);
+ return err;
+ }
+ }
+
return 0;
}
+static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
+ struct sockaddr_storage saddr;
+ socklen_t slen;
+
+ if (domain == AF_UNSPEC) {
+ handle->flags |= flags;
+ return 0;
+ }
+
+ if (uv__stream_fd(handle) != -1) {
+
+ if (flags & UV_HANDLE_BOUND) {
+
+ if (handle->flags & UV_HANDLE_BOUND) {
+ /* It is already bound to a port. */
+ handle->flags |= flags;
+ return 0;
+ }
+
+ /* Query to see if tcp socket is bound. */
+ slen = sizeof(saddr);
+ memset(&saddr, 0, sizeof(saddr));
+ if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen))
+ return -errno;
+
+ if ((saddr.ss_family == AF_INET6 &&
+ ((struct sockaddr_in6*) &saddr)->sin6_port != 0) ||
+ (saddr.ss_family == AF_INET &&
+ ((struct sockaddr_in*) &saddr)->sin_port != 0)) {
+ /* Handle is already bound to a port. */
+ handle->flags |= flags;
+ return 0;
+ }
+
+ /* Bind to arbitrary port */
+ if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen))
+ return -errno;
+ }
+
+ handle->flags |= flags;
+ return 0;
+ }
+
+ return new_socket(handle, domain, flags);
+}
+
+
int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
int domain;
@@ -260,6 +321,7 @@ int uv_tcp_getpeername(const uv_tcp_t* handle,
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
static int single_accept = -1;
+ unsigned long flags;
int err;
if (tcp->delayed_error)
@@ -273,30 +335,17 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
if (single_accept)
tcp->flags |= UV_TCP_SINGLE_ACCEPT;
- err = maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE);
- if (err)
- return err;
-
-#ifdef __MVS__
+ flags = UV_STREAM_READABLE;
+#if defined(__MVS__)
/* on zOS the listen call does not bind automatically
if the socket is unbound. Hence the manual binding to
an arbitrary port is required to be done manually
*/
-
- if (!(tcp->flags & UV_HANDLE_BOUND)) {
- struct sockaddr_storage saddr;
- socklen_t slen = sizeof(saddr);
- memset(&saddr, 0, sizeof(saddr));
-
- if (getsockname(tcp->io_watcher.fd, (struct sockaddr*) &saddr, &slen))
- return -errno;
-
- if (bind(tcp->io_watcher.fd, (struct sockaddr*) &saddr, slen))
- return -errno;
-
- tcp->flags |= UV_HANDLE_BOUND;
- }
-#endif
+ flags |= UV_HANDLE_BOUND;
+#endif
+ err = maybe_new_socket(tcp, AF_INET, flags);
+ if (err)
+ return err;
if (listen(tcp->io_watcher.fd, backlog))
return -errno;
diff --git a/Utilities/cmlibuv/src/unix/thread.c b/Utilities/cmlibuv/src/unix/thread.c
index a9b5e4c..abaca29 100644
--- a/Utilities/cmlibuv/src/unix/thread.c
+++ b/Utilities/cmlibuv/src/unix/thread.c
@@ -41,36 +41,159 @@
#define NANOSEC ((uint64_t) 1e9)
-int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
- int err;
- pthread_attr_t* attr;
-#if defined(__APPLE__)
- pthread_attr_t attr_storage;
- struct rlimit lim;
+#if defined(UV__PTHREAD_BARRIER_FALLBACK)
+/* TODO: support barrier_attr */
+int pthread_barrier_init(pthread_barrier_t* barrier,
+ const void* barrier_attr,
+ unsigned count) {
+ int rc;
+ _uv_barrier* b;
+
+ if (barrier == NULL || count == 0)
+ return EINVAL;
+
+ if (barrier_attr != NULL)
+ return ENOTSUP;
+
+ b = uv__malloc(sizeof(*b));
+ if (b == NULL)
+ return ENOMEM;
+
+ b->in = 0;
+ b->out = 0;
+ b->threshold = count;
+
+ if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0)
+ goto error2;
+ if ((rc = pthread_cond_init(&b->cond, NULL)) != 0)
+ goto error;
+
+ barrier->b = b;
+ return 0;
+
+error:
+ pthread_mutex_destroy(&b->mutex);
+error2:
+ uv__free(b);
+ return rc;
+}
+
+int pthread_barrier_wait(pthread_barrier_t* barrier) {
+ int rc;
+ _uv_barrier* b;
+
+ if (barrier == NULL || barrier->b == NULL)
+ return EINVAL;
+
+ b = barrier->b;
+ /* Lock the mutex*/
+ if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
+ return rc;
+
+ /* Increment the count. If this is the first thread to reach the threshold,
+ wake up waiters, unlock the mutex, then return
+ PTHREAD_BARRIER_SERIAL_THREAD. */
+ if (++b->in == b->threshold) {
+ b->in = 0;
+ b->out = b->threshold - 1;
+ rc = pthread_cond_signal(&b->cond);
+ assert(rc == 0);
+
+ pthread_mutex_unlock(&b->mutex);
+ return PTHREAD_BARRIER_SERIAL_THREAD;
+ }
+ /* Otherwise, wait for other threads until in is set to 0,
+ then return 0 to indicate this is not the first thread. */
+ do {
+ if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0)
+ break;
+ } while (b->in != 0);
+
+ /* mark thread exit */
+ b->out--;
+ pthread_cond_signal(&b->cond);
+ pthread_mutex_unlock(&b->mutex);
+ return rc;
+}
+
+int pthread_barrier_destroy(pthread_barrier_t* barrier) {
+ int rc;
+ _uv_barrier* b;
+
+ if (barrier == NULL || barrier->b == NULL)
+ return EINVAL;
+
+ b = barrier->b;
+
+ if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
+ return rc;
+
+ if (b->in > 0 || b->out > 0)
+ rc = EBUSY;
+
+ pthread_mutex_unlock(&b->mutex);
+
+ if (rc)
+ return rc;
+
+ pthread_cond_destroy(&b->cond);
+ pthread_mutex_destroy(&b->mutex);
+ uv__free(barrier->b);
+ barrier->b = NULL;
+ return 0;
+}
#endif
- /* On OSX threads other than the main thread are created with a reduced stack
- * size by default, adjust it to RLIMIT_STACK.
- */
-#if defined(__APPLE__)
- if (getrlimit(RLIMIT_STACK, &lim))
- abort();
- attr = &attr_storage;
- if (pthread_attr_init(attr))
+/* On MacOS, threads other than the main thread are created with a reduced
+ * stack size by default. Adjust to RLIMIT_STACK aligned to the page size.
+ *
+ * On Linux, threads created by musl have a much smaller stack than threads
+ * created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency.
+ */
+static size_t thread_stack_size(void) {
+#if defined(__APPLE__) || defined(__linux__)
+ struct rlimit lim;
+
+ if (getrlimit(RLIMIT_STACK, &lim))
abort();
if (lim.rlim_cur != RLIM_INFINITY) {
/* pthread_attr_setstacksize() expects page-aligned values. */
lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize();
-
if (lim.rlim_cur >= PTHREAD_STACK_MIN)
- if (pthread_attr_setstacksize(attr, lim.rlim_cur))
- abort();
+ return lim.rlim_cur;
}
+#endif
+
+#if !defined(__linux__)
+ return 0;
+#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__)
+ return 4 << 20; /* glibc default. */
#else
- attr = NULL;
+ return 2 << 20; /* glibc default. */
#endif
+}
+
+
+int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
+ int err;
+ size_t stack_size;
+ pthread_attr_t* attr;
+ pthread_attr_t attr_storage;
+
+ attr = NULL;
+ stack_size = thread_stack_size();
+
+ if (stack_size > 0) {
+ attr = &attr_storage;
+
+ if (pthread_attr_init(attr))
+ abort();
+
+ if (pthread_attr_setstacksize(attr, stack_size))
+ abort();
+ }
err = pthread_create(tid, attr, (void*(*)(void*)) entry, arg);
@@ -118,6 +241,25 @@ int uv_mutex_init(uv_mutex_t* mutex) {
}
+int uv_mutex_init_recursive(uv_mutex_t* mutex) {
+ pthread_mutexattr_t attr;
+ int err;
+
+ if (pthread_mutexattr_init(&attr))
+ abort();
+
+ if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
+ abort();
+
+ err = pthread_mutex_init(mutex, &attr);
+
+ if (pthread_mutexattr_destroy(&attr))
+ abort();
+
+ return -err;
+}
+
+
void uv_mutex_destroy(uv_mutex_t* mutex) {
if (pthread_mutex_destroy(mutex))
abort();
@@ -281,18 +423,20 @@ int uv_sem_trywait(uv_sem_t* sem) {
int uv_sem_init(uv_sem_t* sem, unsigned int value) {
uv_sem_t semid;
- struct sembuf buf;
int err;
+ union {
+ int val;
+ struct semid_ds* buf;
+ unsigned short* array;
+ } arg;
- buf.sem_num = 0;
- buf.sem_op = value;
- buf.sem_flg = 0;
semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR);
if (semid == -1)
return -errno;
- if (-1 == semop(semid, &buf, 1)) {
+ arg.val = value;
+ if (-1 == semctl(semid, 0, SETVAL, arg)) {
err = errno;
if (-1 == semctl(*sem, 0, IPC_RMID))
abort();
@@ -424,7 +568,7 @@ int uv_cond_init(uv_cond_t* cond) {
if (err)
return -err;
-#if !(defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
+#if !(defined(__ANDROID_API__) && __ANDROID_API__ < 21)
err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
if (err)
goto error2;
@@ -511,7 +655,8 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
timeout += uv__hrtime(UV_CLOCK_PRECISE);
ts.tv_sec = timeout / NANOSEC;
ts.tv_nsec = timeout % NANOSEC;
-#if defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+
/*
* The bionic pthread implementation doesn't support CLOCK_MONOTONIC,
* but has this alternative function instead.
@@ -519,7 +664,7 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
r = pthread_cond_timedwait_monotonic_np(cond, mutex, &ts);
#else
r = pthread_cond_timedwait(cond, mutex, &ts);
-#endif /* __ANDROID__ */
+#endif /* __ANDROID_API__ */
#endif
diff --git a/Utilities/cmlibuv/src/unix/tty.c b/Utilities/cmlibuv/src/unix/tty.c
index ae1018f..fc8c3ab 100644
--- a/Utilities/cmlibuv/src/unix/tty.c
+++ b/Utilities/cmlibuv/src/unix/tty.c
@@ -48,6 +48,42 @@ static int uv__tty_is_slave(const int fd) {
char dummy[256];
result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0;
+#elif defined(__NetBSD__)
+ /*
+ * NetBSD as an extension returns with ptsname(3) and ptsname_r(3) the slave
+ * device name for both descriptors, the master one and slave one.
+ *
+ * Implement function to compare major device number with pts devices.
+ *
+ * The major numbers are machine-dependent, on NetBSD/amd64 they are
+ * respectively:
+ * - master tty: ptc - major 6
+ * - slave tty: pts - major 5
+ */
+
+ struct stat sb;
+ /* Lookup device's major for the pts driver and cache it. */
+ static devmajor_t pts = NODEVMAJOR;
+
+ if (pts == NODEVMAJOR) {
+ pts = getdevmajor("pts", S_IFCHR);
+ if (pts == NODEVMAJOR)
+ abort();
+ }
+
+ /* Lookup stat structure behind the file descriptor. */
+ if (fstat(fd, &sb) != 0)
+ abort();
+
+ /* Assert character device. */
+ if (!S_ISCHR(sb.st_mode))
+ abort();
+
+ /* Assert valid major. */
+ if (major(sb.st_rdev) == NODEVMAJOR)
+ abort();
+
+ result = (pts == major(sb.st_rdev));
#else
/* Fallback to ptsname
*/
diff --git a/Utilities/cmlibuv/src/unix/udp.c b/Utilities/cmlibuv/src/unix/udp.c
index c556325..a475bf5 100644
--- a/Utilities/cmlibuv/src/unix/udp.c
+++ b/Utilities/cmlibuv/src/unix/udp.c
@@ -237,8 +237,10 @@ static void uv__udp_sendmsg(uv_udp_t* handle) {
size = sendmsg(handle->io_watcher.fd, &h, 0);
} while (size == -1 && errno == EINTR);
- if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
- break;
+ if (size == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
+ break;
+ }
req->status = (size == -1 ? -errno : size);
@@ -472,7 +474,7 @@ int uv__udp_try_send(uv_udp_t* handle,
} while (size == -1 && errno == EINTR);
if (size == -1) {
- if (errno == EAGAIN || errno == EWOULDBLOCK)
+ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
return -EAGAIN;
else
return -errno;
diff --git a/Utilities/cmlibuv/src/uv-data-getter-setters.c b/Utilities/cmlibuv/src/uv-data-getter-setters.c
new file mode 100644
index 0000000..533e4a2
--- /dev/null
+++ b/Utilities/cmlibuv/src/uv-data-getter-setters.c
@@ -0,0 +1,96 @@
+#include "uv.h"
+
+const char* uv_handle_type_name(uv_handle_type type) {
+ switch (type) {
+#define XX(uc,lc) case UV_##uc: return #lc;
+ UV_HANDLE_TYPE_MAP(XX)
+#undef XX
+ case UV_FILE: return "file";
+ case UV_HANDLE_TYPE_MAX:
+ case UV_UNKNOWN_HANDLE: return NULL;
+ }
+ return NULL;
+}
+
+uv_handle_type uv_handle_get_type(const uv_handle_t* handle) {
+ return handle->type;
+}
+
+void* uv_handle_get_data(const uv_handle_t* handle) {
+ return handle->data;
+}
+
+uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle) {
+ return handle->loop;
+}
+
+void uv_handle_set_data(uv_handle_t* handle, void* data) {
+ handle->data = data;
+}
+
+const char* uv_req_type_name(uv_req_type type) {
+ switch (type) {
+#define XX(uc,lc) case UV_##uc: return #lc;
+ UV_REQ_TYPE_MAP(XX)
+#undef XX
+ case UV_REQ_TYPE_MAX:
+ case UV_UNKNOWN_REQ: return NULL;
+ }
+ return NULL;
+}
+
+uv_req_type uv_req_get_type(const uv_req_t* req) {
+ return req->type;
+}
+
+void* uv_req_get_data(const uv_req_t* req) {
+ return req->data;
+}
+
+void uv_req_set_data(uv_req_t* req, void* data) {
+ req->data = data;
+}
+
+size_t uv_stream_get_write_queue_size(const uv_stream_t* stream) {
+ return stream->write_queue_size;
+}
+
+size_t uv_udp_get_send_queue_size(const uv_udp_t* handle) {
+ return handle->send_queue_size;
+}
+
+size_t uv_udp_get_send_queue_count(const uv_udp_t* handle) {
+ return handle->send_queue_count;
+}
+
+uv_pid_t uv_process_get_pid(const uv_process_t* proc) {
+ return proc->pid;
+}
+
+uv_fs_type uv_fs_get_type(const uv_fs_t* req) {
+ return req->fs_type;
+}
+
+ssize_t uv_fs_get_result(const uv_fs_t* req) {
+ return req->result;
+}
+
+void* uv_fs_get_ptr(const uv_fs_t* req) {
+ return req->ptr;
+}
+
+const char* uv_fs_get_path(const uv_fs_t* req) {
+ return req->path;
+}
+
+uv_stat_t* uv_fs_get_statbuf(uv_fs_t* req) {
+ return &req->statbuf;
+}
+
+void* uv_loop_get_data(const uv_loop_t* loop) {
+ return loop->data;
+}
+
+void uv_loop_set_data(uv_loop_t* loop, void* data) {
+ loop->data = data;
+}
diff --git a/Utilities/cmlibuv/src/win/dl.c b/Utilities/cmlibuv/src/win/dl.c
index 39e400a..97ac1c1 100644
--- a/Utilities/cmlibuv/src/win/dl.c
+++ b/Utilities/cmlibuv/src/win/dl.c
@@ -22,7 +22,7 @@
#include "uv.h"
#include "internal.h"
-static int uv__dlerror(uv_lib_t* lib, int errorno);
+static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno);
int uv_dlopen(const char* filename, uv_lib_t* lib) {
@@ -37,12 +37,12 @@ int uv_dlopen(const char* filename, uv_lib_t* lib) {
-1,
filename_w,
ARRAY_SIZE(filename_w))) {
- return uv__dlerror(lib, GetLastError());
+ return uv__dlerror(lib, filename, GetLastError());
}
lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (lib->handle == NULL) {
- return uv__dlerror(lib, GetLastError());
+ return uv__dlerror(lib, filename, GetLastError());
}
return 0;
@@ -65,7 +65,7 @@ void uv_dlclose(uv_lib_t* lib) {
int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
*ptr = (void*) GetProcAddress(lib->handle, name);
- return uv__dlerror(lib, *ptr ? 0 : GetLastError());
+ return uv__dlerror(lib, "", *ptr ? 0 : GetLastError());
}
@@ -88,31 +88,46 @@ static void uv__format_fallback_error(uv_lib_t* lib, int errorno){
-static int uv__dlerror(uv_lib_t* lib, int errorno) {
+static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno) {
+ DWORD_PTR arg;
DWORD res;
+ char* msg;
if (lib->errmsg) {
- LocalFree((void*)lib->errmsg);
+ LocalFree(lib->errmsg);
lib->errmsg = NULL;
}
- if (errorno) {
+ if (errorno == 0)
+ return 0;
+
+ res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ (LPSTR) &lib->errmsg, 0, NULL);
+
+ if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
- MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
- (LPSTR) &lib->errmsg, 0, NULL);
- if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
- res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
- 0, (LPSTR) &lib->errmsg, 0, NULL);
- }
-
- if (!res) {
- uv__format_fallback_error(lib, errorno);
- }
+ 0, (LPSTR) &lib->errmsg, 0, NULL);
+ }
+
+ if (res && errorno == ERROR_BAD_EXE_FORMAT && strstr(lib->errmsg, "%1")) {
+ msg = lib->errmsg;
+ lib->errmsg = NULL;
+ arg = (DWORD_PTR) filename;
+ res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_ARGUMENT_ARRAY |
+ FORMAT_MESSAGE_FROM_STRING,
+ msg,
+ 0, 0, (LPSTR) &lib->errmsg, 0, (va_list*) &arg);
+ LocalFree(msg);
}
- return errorno ? -1 : 0;
+ if (!res)
+ uv__format_fallback_error(lib, errorno);
+
+ return -1;
}
diff --git a/Utilities/cmlibuv/src/win/error.c b/Utilities/cmlibuv/src/win/error.c
index 642d111..9b03bfe 100644
--- a/Utilities/cmlibuv/src/win/error.c
+++ b/Utilities/cmlibuv/src/win/error.c
@@ -58,7 +58,7 @@ void uv_fatal_error(const int errorno, const char* syscall) {
LocalFree(buf);
}
- *((char*)NULL) = 0xff; /* Force debug break */
+ DebugBreak();
abort();
}
diff --git a/Utilities/cmlibuv/src/win/fs.c b/Utilities/cmlibuv/src/win/fs.c
index 2d72cdc..097b00e 100644
--- a/Utilities/cmlibuv/src/win/fs.c
+++ b/Utilities/cmlibuv/src/win/fs.c
@@ -43,11 +43,26 @@
#define UV_FS_CLEANEDUP 0x0010
-#define QUEUE_FS_TP_JOB(loop, req) \
- do { \
- uv__req_register(loop, req); \
- uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done); \
- } while (0)
+#define INIT(subtype) \
+ do { \
+ if (req == NULL) \
+ return UV_EINVAL; \
+ uv_fs_req_init(loop, req, subtype, cb); \
+ } \
+ while (0)
+
+#define POST \
+ do { \
+ if (cb != NULL) { \
+ uv__req_register(loop, req); \
+ uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \
+ return 0; \
+ } else { \
+ uv__fs_work(&req->work_req); \
+ return req->result; \
+ } \
+ } \
+ while (0)
#define SET_REQ_RESULT(req, result_value) \
do { \
@@ -113,6 +128,7 @@ const WCHAR LONG_PATH_PREFIX_LEN = 4;
const WCHAR UNC_PATH_PREFIX[] = L"\\\\?\\UNC\\";
const WCHAR UNC_PATH_PREFIX_LEN = 8;
+static int uv__file_symlink_usermode_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
void uv_fs_init(void) {
_fmode = _O_BINARY;
@@ -220,6 +236,7 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
uv_fs_type fs_type, const uv_fs_cb cb) {
+ uv__once_init();
UV_REQ_INIT(req, UV_FS);
req->loop = loop;
req->flags = 0;
@@ -398,21 +415,21 @@ void fs__open(uv_fs_t* req) {
umask(current_umask);
/* convert flags and mode to CreateFile parameters */
- switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
- case _O_RDONLY:
+ switch (flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR)) {
+ case UV_FS_O_RDONLY:
access = FILE_GENERIC_READ;
break;
- case _O_WRONLY:
+ case UV_FS_O_WRONLY:
access = FILE_GENERIC_WRITE;
break;
- case _O_RDWR:
+ case UV_FS_O_RDWR:
access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
break;
default:
goto einval;
}
- if (flags & _O_APPEND) {
+ if (flags & UV_FS_O_APPEND) {
access &= ~FILE_WRITE_DATA;
access |= FILE_APPEND_DATA;
}
@@ -422,26 +439,33 @@ void fs__open(uv_fs_t* req) {
* does. We indiscriminately use all the sharing modes, to match
* UNIX semantics. In particular, this ensures that the file can
* be deleted even whilst it's open, fixing issue #1449.
+ * We still support exclusive sharing mode, since it is necessary
+ * for opening raw block devices, otherwise Windows will prevent
+ * any attempt to write past the master boot record.
*/
- share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ if (flags & UV_FS_O_EXLOCK) {
+ share = 0;
+ } else {
+ share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ }
- switch (flags & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
+ switch (flags & (UV_FS_O_CREAT | UV_FS_O_EXCL | UV_FS_O_TRUNC)) {
case 0:
- case _O_EXCL:
+ case UV_FS_O_EXCL:
disposition = OPEN_EXISTING;
break;
- case _O_CREAT:
+ case UV_FS_O_CREAT:
disposition = OPEN_ALWAYS;
break;
- case _O_CREAT | _O_EXCL:
- case _O_CREAT | _O_TRUNC | _O_EXCL:
+ case UV_FS_O_CREAT | UV_FS_O_EXCL:
+ case UV_FS_O_CREAT | UV_FS_O_TRUNC | UV_FS_O_EXCL:
disposition = CREATE_NEW;
break;
- case _O_TRUNC:
- case _O_TRUNC | _O_EXCL:
+ case UV_FS_O_TRUNC:
+ case UV_FS_O_TRUNC | UV_FS_O_EXCL:
disposition = TRUNCATE_EXISTING;
break;
- case _O_CREAT | _O_TRUNC:
+ case UV_FS_O_CREAT | UV_FS_O_TRUNC:
disposition = CREATE_ALWAYS;
break;
default:
@@ -449,34 +473,49 @@ void fs__open(uv_fs_t* req) {
}
attributes |= FILE_ATTRIBUTE_NORMAL;
- if (flags & _O_CREAT) {
+ if (flags & UV_FS_O_CREAT) {
if (!((req->fs.info.mode & ~current_umask) & _S_IWRITE)) {
attributes |= FILE_ATTRIBUTE_READONLY;
}
}
- if (flags & _O_TEMPORARY ) {
+ if (flags & UV_FS_O_TEMPORARY ) {
attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY;
access |= DELETE;
}
- if (flags & _O_SHORT_LIVED) {
+ if (flags & UV_FS_O_SHORT_LIVED) {
attributes |= FILE_ATTRIBUTE_TEMPORARY;
}
- switch (flags & (_O_SEQUENTIAL | _O_RANDOM)) {
+ switch (flags & (UV_FS_O_SEQUENTIAL | UV_FS_O_RANDOM)) {
case 0:
break;
- case _O_SEQUENTIAL:
+ case UV_FS_O_SEQUENTIAL:
attributes |= FILE_FLAG_SEQUENTIAL_SCAN;
break;
- case _O_RANDOM:
+ case UV_FS_O_RANDOM:
attributes |= FILE_FLAG_RANDOM_ACCESS;
break;
default:
goto einval;
}
+ if (flags & UV_FS_O_DIRECT) {
+ attributes |= FILE_FLAG_NO_BUFFERING;
+ }
+
+ switch (flags & (UV_FS_O_DSYNC | UV_FS_O_SYNC)) {
+ case 0:
+ break;
+ case UV_FS_O_DSYNC:
+ case UV_FS_O_SYNC:
+ attributes |= FILE_FLAG_WRITE_THROUGH;
+ break;
+ default:
+ goto einval;
+ }
+
/* Setting this flag makes it possible to open a directory. */
attributes |= FILE_FLAG_BACKUP_SEMANTICS;
@@ -489,9 +528,9 @@ void fs__open(uv_fs_t* req) {
NULL);
if (file == INVALID_HANDLE_VALUE) {
DWORD error = GetLastError();
- if (error == ERROR_FILE_EXISTS && (flags & _O_CREAT) &&
- !(flags & _O_EXCL)) {
- /* Special case: when ERROR_FILE_EXISTS happens and O_CREAT was */
+ if (error == ERROR_FILE_EXISTS && (flags & UV_FS_O_CREAT) &&
+ !(flags & UV_FS_O_EXCL)) {
+ /* Special case: when ERROR_FILE_EXISTS happens and UV_FS_O_CREAT was */
/* specified, it means the path referred to a directory. */
SET_REQ_UV_ERROR(req, UV_EISDIR, error);
} else {
@@ -556,9 +595,14 @@ void fs__read(uv_fs_t* req) {
DWORD error;
int result;
unsigned int index;
+ LARGE_INTEGER original_position;
+ LARGE_INTEGER zero_offset;
+ int restore_position;
VERIFY_FD(fd, req);
+ zero_offset.QuadPart = 0;
+ restore_position = 0;
handle = uv__get_osfhandle(fd);
if (handle == INVALID_HANDLE_VALUE) {
@@ -569,6 +613,10 @@ void fs__read(uv_fs_t* req) {
if (offset != -1) {
memset(&overlapped, 0, sizeof overlapped);
overlapped_ptr = &overlapped;
+ if (SetFilePointerEx(handle, zero_offset, &original_position,
+ FILE_CURRENT)) {
+ restore_position = 1;
+ }
} else {
overlapped_ptr = NULL;
}
@@ -593,6 +641,9 @@ void fs__read(uv_fs_t* req) {
++index;
} while (result && index < req->fs.info.nbufs);
+ if (restore_position)
+ SetFilePointerEx(handle, original_position, NULL, FILE_BEGIN);
+
if (result || bytes > 0) {
SET_REQ_RESULT(req, bytes);
} else {
@@ -615,9 +666,14 @@ void fs__write(uv_fs_t* req) {
DWORD bytes;
int result;
unsigned int index;
+ LARGE_INTEGER original_position;
+ LARGE_INTEGER zero_offset;
+ int restore_position;
VERIFY_FD(fd, req);
+ zero_offset.QuadPart = 0;
+ restore_position = 0;
handle = uv__get_osfhandle(fd);
if (handle == INVALID_HANDLE_VALUE) {
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
@@ -627,6 +683,10 @@ void fs__write(uv_fs_t* req) {
if (offset != -1) {
memset(&overlapped, 0, sizeof overlapped);
overlapped_ptr = &overlapped;
+ if (SetFilePointerEx(handle, zero_offset, &original_position,
+ FILE_CURRENT)) {
+ restore_position = 1;
+ }
} else {
overlapped_ptr = NULL;
}
@@ -651,6 +711,9 @@ void fs__write(uv_fs_t* req) {
++index;
} while (result && index < req->fs.info.nbufs);
+ if (restore_position)
+ SetFilePointerEx(handle, original_position, NULL, FILE_BEGIN);
+
if (result || bytes > 0) {
SET_REQ_RESULT(req, bytes);
} else {
@@ -1029,7 +1092,8 @@ cleanup:
}
-INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) {
+INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
+ int do_lstat) {
FILE_ALL_INFORMATION file_info;
FILE_FS_VOLUME_INFORMATION volume_info;
NTSTATUS nt_status;
@@ -1084,19 +1148,25 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) {
*/
statbuf->st_mode = 0;
- if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ /*
+ * On Windows, FILE_ATTRIBUTE_REPARSE_POINT is a general purpose mechanism
+ * by which filesystem drivers can intercept and alter file system requests.
+ *
+ * The only reparse points we care about are symlinks and mount points, both
+ * of which are treated as POSIX symlinks. Further, we only care when
+ * invoked via lstat, which seeks information about the link instead of its
+ * target. Otherwise, reparse points must be treated as regular files.
+ */
+ if (do_lstat &&
+ (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
/*
- * It is possible for a file to have FILE_ATTRIBUTE_REPARSE_POINT but not have
- * any link data. In that case DeviceIoControl() in fs__readlink_handle() sets
- * the last error to ERROR_NOT_A_REPARSE_POINT. Then the stat result mode
- * calculated below will indicate a normal directory or file, as if
- * FILE_ATTRIBUTE_REPARSE_POINT was not present.
+ * If reading the link fails, the reparse point is not a symlink and needs
+ * to be treated as a regular file. The higher level lstat function will
+ * detect this failure and retry without do_lstat if appropriate.
*/
- if (fs__readlink_handle(handle, NULL, &statbuf->st_size) == 0) {
- statbuf->st_mode |= S_IFLNK;
- } else if (GetLastError() != ERROR_NOT_A_REPARSE_POINT) {
+ if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0)
return -1;
- }
+ statbuf->st_mode |= S_IFLNK;
}
if (statbuf->st_mode == 0) {
@@ -1139,8 +1209,12 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) {
*
* Therefore we'll just report a sensible value that's quite commonly okay
* on modern hardware.
+ *
+ * 4096 is the minimum required to be compatible with newer Advanced Format
+ * drives (which have 4096 bytes per physical sector), and to be backwards
+ * compatible with older drives (which have 512 bytes per physical sector).
*/
- statbuf->st_blksize = 2048;
+ statbuf->st_blksize = 4096;
/* Todo: set st_flags to something meaningful. Also provide a wrapper for
* chattr(2).
@@ -1191,9 +1265,11 @@ INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
return;
}
- if (fs__stat_handle(handle, &req->statbuf) != 0) {
+ if (fs__stat_handle(handle, &req->statbuf, do_lstat) != 0) {
DWORD error = GetLastError();
- if (do_lstat && error == ERROR_SYMLINK_NOT_SUPPORTED) {
+ if (do_lstat &&
+ (error == ERROR_SYMLINK_NOT_SUPPORTED ||
+ error == ERROR_NOT_A_REPARSE_POINT)) {
/* We opened a reparse point but it was not a symlink. Try again. */
fs__stat_impl(req, 0);
@@ -1237,7 +1313,7 @@ static void fs__fstat(uv_fs_t* req) {
return;
}
- if (fs__stat_handle(handle, &req->statbuf) != 0) {
+ if (fs__stat_handle(handle, &req->statbuf, 0) != 0) {
SET_REQ_WIN32_ERROR(req, GetLastError());
return;
}
@@ -1309,6 +1385,22 @@ static void fs__ftruncate(uv_fs_t* req) {
}
+static void fs__copyfile(uv_fs_t* req) {
+ int flags;
+ int overwrite;
+
+ flags = req->fs.info.file_flags;
+ overwrite = flags & UV_FS_COPYFILE_EXCL;
+
+ if (CopyFileW(req->file.pathw, req->fs.info.new_pathw, overwrite) == 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ SET_REQ_RESULT(req, 0);
+}
+
+
static void fs__sendfile(uv_fs_t* req) {
int fd_in = req->file.fd, fd_out = req->fs.info.fd_out;
size_t length = req->fs.info.bufsml[0].len;
@@ -1675,25 +1767,46 @@ error:
static void fs__symlink(uv_fs_t* req) {
- WCHAR* pathw = req->file.pathw;
- WCHAR* new_pathw = req->fs.info.new_pathw;
- int flags = req->fs.info.file_flags;
- int result;
+ WCHAR* pathw;
+ WCHAR* new_pathw;
+ int flags;
+ int err;
+ pathw = req->file.pathw;
+ new_pathw = req->fs.info.new_pathw;
- if (flags & UV_FS_SYMLINK_JUNCTION) {
+ if (req->fs.info.file_flags & UV_FS_SYMLINK_JUNCTION) {
fs__create_junction(req, pathw, new_pathw);
- } else if (pCreateSymbolicLinkW) {
- result = pCreateSymbolicLinkW(new_pathw,
- pathw,
- flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1;
- if (result == -1) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- } else {
- SET_REQ_RESULT(req, result);
- }
- } else {
+ return;
+ }
+ if (!pCreateSymbolicLinkW) {
SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
+ return;
+ }
+
+ if (req->fs.info.file_flags & UV_FS_SYMLINK_DIR)
+ flags = SYMBOLIC_LINK_FLAG_DIRECTORY | uv__file_symlink_usermode_flag;
+ else
+ flags = uv__file_symlink_usermode_flag;
+
+ if (pCreateSymbolicLinkW(new_pathw, pathw, flags)) {
+ SET_REQ_RESULT(req, 0);
+ return;
+ }
+
+ /* Something went wrong. We will test if it is because of user-mode
+ * symlinks.
+ */
+ err = GetLastError();
+ if (err == ERROR_INVALID_PARAMETER &&
+ flags & SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) {
+ /* This system does not support user-mode symlinks. We will clear the
+ * unsupported flag and retry.
+ */
+ uv__file_symlink_usermode_flag = 0;
+ fs__symlink(req);
+ } else {
+ SET_REQ_WIN32_ERROR(req, err);
}
}
@@ -1831,6 +1944,7 @@ static void uv__fs_work(struct uv__work* w) {
XX(CLOSE, close)
XX(READ, read)
XX(WRITE, write)
+ XX(COPYFILE, copyfile)
XX(SENDFILE, sendfile)
XX(STAT, stat)
XX(LSTAT, lstat)
@@ -1877,6 +1991,9 @@ static void uv__fs_done(struct uv__work* w, int status) {
void uv_fs_req_cleanup(uv_fs_t* req) {
+ if (req == NULL)
+ return;
+
if (req->flags & UV_FS_CLEANEDUP)
return;
@@ -1907,8 +2024,7 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
int mode, uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_OPEN, cb);
-
+ INIT(UV_FS_OPEN);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
@@ -1916,28 +2032,14 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
req->fs.info.file_flags = flags;
req->fs.info.mode = mode;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__open(req);
- return req->result;
- }
+ POST;
}
int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
- uv_fs_req_init(loop, req, UV_FS_CLOSE, cb);
+ INIT(UV_FS_CLOSE);
req->file.fd = fd;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__close(req);
- return req->result;
- }
+ POST;
}
@@ -1948,11 +2050,11 @@ int uv_fs_read(uv_loop_t* loop,
unsigned int nbufs,
int64_t offset,
uv_fs_cb cb) {
+ INIT(UV_FS_READ);
+
if (bufs == NULL || nbufs == 0)
return UV_EINVAL;
- uv_fs_req_init(loop, req, UV_FS_READ, cb);
-
req->file.fd = fd;
req->fs.info.nbufs = nbufs;
@@ -1966,14 +2068,7 @@ int uv_fs_read(uv_loop_t* loop,
memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
req->fs.info.offset = offset;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__read(req);
- return req->result;
- }
+ POST;
}
@@ -1984,11 +2079,11 @@ int uv_fs_write(uv_loop_t* loop,
unsigned int nbufs,
int64_t offset,
uv_fs_cb cb) {
+ INIT(UV_FS_WRITE);
+
if (bufs == NULL || nbufs == 0)
return UV_EINVAL;
- uv_fs_req_init(loop, req, UV_FS_WRITE, cb);
-
req->file.fd = fd;
req->fs.info.nbufs = nbufs;
@@ -2002,14 +2097,7 @@ int uv_fs_write(uv_loop_t* loop,
memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
req->fs.info.offset = offset;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__write(req);
- return req->result;
- }
+ POST;
}
@@ -2017,20 +2105,13 @@ int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_UNLINK, cb);
-
+ INIT(UV_FS_UNLINK);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__unlink(req);
- return req->result;
- }
+ POST;
}
@@ -2038,22 +2119,14 @@ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_MKDIR, cb);
-
+ INIT(UV_FS_MKDIR);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
req->fs.info.mode = mode;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__mkdir(req);
- return req->result;
- }
+ POST;
}
@@ -2061,39 +2134,25 @@ int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl,
uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_MKDTEMP, cb);
-
+ INIT(UV_FS_MKDTEMP);
err = fs__capture_path(req, tpl, NULL, TRUE);
if (err)
return uv_translate_sys_error(err);
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__mkdtemp(req);
- return req->result;
- }
+ POST;
}
int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_RMDIR, cb);
-
+ INIT(UV_FS_RMDIR);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__rmdir(req);
- return req->result;
- }
+ POST;
}
@@ -2101,22 +2160,14 @@ int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_SCANDIR, cb);
-
+ INIT(UV_FS_SCANDIR);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
req->fs.info.file_flags = flags;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__scandir(req);
- return req->result;
- }
+ POST;
}
@@ -2124,20 +2175,13 @@ int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
const char* new_path, uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_LINK, cb);
-
+ INIT(UV_FS_LINK);
err = fs__capture_path(req, path, new_path, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__link(req);
- return req->result;
- }
+ POST;
}
@@ -2145,22 +2189,14 @@ int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
const char* new_path, int flags, uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_SYMLINK, cb);
-
+ INIT(UV_FS_SYMLINK);
err = fs__capture_path(req, path, new_path, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
req->fs.info.file_flags = flags;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__symlink(req);
- return req->result;
- }
+ POST;
}
@@ -2168,20 +2204,13 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_READLINK, cb);
-
+ INIT(UV_FS_READLINK);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__readlink(req);
- return req->result;
- }
+ POST;
}
@@ -2189,24 +2218,18 @@ int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path,
uv_fs_cb cb) {
int err;
- if (!req || !path) {
+ INIT(UV_FS_REALPATH);
+
+ if (!path) {
return UV_EINVAL;
}
- uv_fs_req_init(loop, req, UV_FS_REALPATH, cb);
-
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__realpath(req);
- return req->result;
- }
+ POST;
}
@@ -2214,88 +2237,53 @@ int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
uv_gid_t gid, uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_CHOWN, cb);
-
+ INIT(UV_FS_CHOWN);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__chown(req);
- return req->result;
- }
+ POST;
}
int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid,
uv_gid_t gid, uv_fs_cb cb) {
- uv_fs_req_init(loop, req, UV_FS_FCHOWN, cb);
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__fchown(req);
- return req->result;
- }
+ INIT(UV_FS_FCHOWN);
+ POST;
}
int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_STAT, cb);
-
+ INIT(UV_FS_STAT);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__stat(req);
- return req->result;
- }
+ POST;
}
int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_LSTAT, cb);
-
+ INIT(UV_FS_LSTAT);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__lstat(req);
- return req->result;
- }
+ POST;
}
int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
- uv_fs_req_init(loop, req, UV_FS_FSTAT, cb);
+ INIT(UV_FS_FSTAT);
req->file.fd = fd;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__fstat(req);
- return req->result;
- }
+ POST;
}
@@ -2303,85 +2291,70 @@ int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
const char* new_path, uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_RENAME, cb);
-
+ INIT(UV_FS_RENAME);
err = fs__capture_path(req, path, new_path, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__rename(req);
- return req->result;
- }
+ POST;
}
int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
- uv_fs_req_init(loop, req, UV_FS_FSYNC, cb);
+ INIT(UV_FS_FSYNC);
req->file.fd = fd;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__fsync(req);
- return req->result;
- }
+ POST;
}
int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
- uv_fs_req_init(loop, req, UV_FS_FDATASYNC, cb);
+ INIT(UV_FS_FDATASYNC);
req->file.fd = fd;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__fdatasync(req);
- return req->result;
- }
+ POST;
}
int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd,
int64_t offset, uv_fs_cb cb) {
- uv_fs_req_init(loop, req, UV_FS_FTRUNCATE, cb);
-
+ INIT(UV_FS_FTRUNCATE);
req->file.fd = fd;
req->fs.info.offset = offset;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__ftruncate(req);
- return req->result;
- }
+ POST;
}
+int uv_fs_copyfile(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ int flags,
+ uv_fs_cb cb) {
+ int err;
+
+ INIT(UV_FS_COPYFILE);
+
+ if (flags & ~UV_FS_COPYFILE_EXCL)
+ return UV_EINVAL;
+
+ err = fs__capture_path(req, path, new_path, cb != NULL);
+
+ if (err)
+ return uv_translate_sys_error(err);
+
+ req->fs.info.file_flags = flags;
+ POST;
+}
+
int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out,
uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) {
- uv_fs_req_init(loop, req, UV_FS_SENDFILE, cb);
-
+ INIT(UV_FS_SENDFILE);
req->file.fd = fd_in;
req->fs.info.fd_out = fd_out;
req->fs.info.offset = in_offset;
req->fs.info.bufsml[0].len = length;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__sendfile(req);
- return req->result;
- }
+ POST;
}
@@ -2392,21 +2365,13 @@ int uv_fs_access(uv_loop_t* loop,
uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_ACCESS, cb);
-
+ INIT(UV_FS_ACCESS);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err)
return uv_translate_sys_error(err);
req->fs.info.mode = flags;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- }
-
- fs__access(req);
- return req->result;
+ POST;
}
@@ -2414,39 +2379,23 @@ int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_CHMOD, cb);
-
+ INIT(UV_FS_CHMOD);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
req->fs.info.mode = mode;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__chmod(req);
- return req->result;
- }
+ POST;
}
int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode,
uv_fs_cb cb) {
- uv_fs_req_init(loop, req, UV_FS_FCHMOD, cb);
-
+ INIT(UV_FS_FCHMOD);
req->file.fd = fd;
req->fs.info.mode = mode;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__fchmod(req);
- return req->result;
- }
+ POST;
}
@@ -2454,8 +2403,7 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
double mtime, uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_UTIME, cb);
-
+ INIT(UV_FS_UTIME);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
@@ -2463,30 +2411,15 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
req->fs.time.atime = atime;
req->fs.time.mtime = mtime;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__utime(req);
- return req->result;
- }
+ POST;
}
int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
double mtime, uv_fs_cb cb) {
- uv_fs_req_init(loop, req, UV_FS_FUTIME, cb);
-
+ INIT(UV_FS_FUTIME);
req->file.fd = fd;
req->fs.time.atime = atime;
req->fs.time.mtime = mtime;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__futime(req);
- return req->result;
- }
+ POST;
}
diff --git a/Utilities/cmlibuv/src/win/getaddrinfo.c b/Utilities/cmlibuv/src/win/getaddrinfo.c
index baab838..282d919 100644
--- a/Utilities/cmlibuv/src/win/getaddrinfo.c
+++ b/Utilities/cmlibuv/src/win/getaddrinfo.c
@@ -28,6 +28,8 @@
/* EAI_* constants. */
#include <winsock2.h>
+/* Needed for ConvertInterfaceIndexToLuid and ConvertInterfaceLuidToNameA */
+#include <iphlpapi.h>
int uv__getaddrinfo_translate_error(int sys_err) {
switch (sys_err) {
@@ -73,6 +75,9 @@ int uv__getaddrinfo_translate_error(int sys_err) {
/* Do we need different versions of this for different architectures? */
#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2)
+#ifndef NDIS_IF_MAX_STRING_SIZE
+#define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE
+#endif
static void uv__getaddrinfo_work(struct uv__work* w) {
uv_getaddrinfo_t* req;
@@ -380,3 +385,69 @@ error:
}
return uv_translate_sys_error(err);
}
+
+int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
+ NET_LUID luid;
+ wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */
+ DWORD bufsize;
+ int r;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return UV_EINVAL;
+
+ r = ConvertInterfaceIndexToLuid(ifindex, &luid);
+
+ if (r != 0)
+ return uv_translate_sys_error(r);
+
+ r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname));
+
+ if (r != 0)
+ return uv_translate_sys_error(r);
+
+ /* Check how much space we need */
+ bufsize = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL);
+
+ if (bufsize == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (bufsize > *size) {
+ *size = bufsize;
+ return UV_ENOBUFS;
+ }
+
+ /* Convert to UTF-8 */
+ bufsize = WideCharToMultiByte(CP_UTF8,
+ 0,
+ wname,
+ -1,
+ buffer,
+ *size,
+ NULL,
+ NULL);
+
+ if (bufsize == 0)
+ return uv_translate_sys_error(GetLastError());
+
+ *size = bufsize - 1;
+ return 0;
+}
+
+int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
+ int r;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return UV_EINVAL;
+
+ r = snprintf(buffer, *size, "%d", ifindex);
+
+ if (r < 0)
+ return uv_translate_sys_error(r);
+
+ if (r >= (int) *size) {
+ *size = r + 1;
+ return UV_ENOBUFS;
+ }
+
+ *size = r;
+ return 0;
+}
diff --git a/Utilities/cmlibuv/src/win/handle.c b/Utilities/cmlibuv/src/win/handle.c
index 72b49d9..3915070 100644
--- a/Utilities/cmlibuv/src/win/handle.c
+++ b/Utilities/cmlibuv/src/win/handle.c
@@ -152,3 +152,8 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) {
int uv_is_closing(const uv_handle_t* handle) {
return !!(handle->flags & (UV__HANDLE_CLOSING | UV_HANDLE_CLOSED));
}
+
+
+uv_os_fd_t uv_get_osfhandle(int fd) {
+ return uv__get_osfhandle(fd);
+}
diff --git a/Utilities/cmlibuv/src/win/internal.h b/Utilities/cmlibuv/src/win/internal.h
index 83601d5..9f28f77 100644
--- a/Utilities/cmlibuv/src/win/internal.h
+++ b/Utilities/cmlibuv/src/win/internal.h
@@ -330,7 +330,6 @@ void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle);
void uv__util_init(void);
uint64_t uv__hrtime(double scale);
-int uv_parent_pid(void);
int uv_current_pid(void);
__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
int uv__getpwuid_r(uv_passwd_t* pwd);
diff --git a/Utilities/cmlibuv/src/win/pipe.c b/Utilities/cmlibuv/src/win/pipe.c
index edf3002..1a7c4dc 100644
--- a/Utilities/cmlibuv/src/win/pipe.c
+++ b/Utilities/cmlibuv/src/win/pipe.c
@@ -31,6 +31,9 @@
#include "stream-inl.h"
#include "req-inl.h"
+#include <aclapi.h>
+#include <accctrl.h>
+
typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t;
struct uv__ipc_queue_item_s {
@@ -202,7 +205,7 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
uv_unique_pipe_name(ptr, name, nameSize);
pipeHandle = CreateNamedPipeA(name,
- access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
+ access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0,
NULL);
@@ -534,7 +537,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
*/
handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name,
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
- FILE_FLAG_FIRST_PIPE_INSTANCE,
+ FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
@@ -803,7 +806,7 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
assert(req->pipeHandle == INVALID_HANDLE_VALUE);
req->pipeHandle = CreateNamedPipeW(handle->name,
- PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
@@ -968,27 +971,31 @@ static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) {
uv_mutex_unlock(m);
}
restart_readfile:
- result = ReadFile(handle->handle,
- &uv_zero_,
- 0,
- &bytes,
- NULL);
- if (!result) {
- err = GetLastError();
- if (err == ERROR_OPERATION_ABORTED &&
- handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
- if (handle->flags & UV_HANDLE_READING) {
- /* just a brief break to do something else */
- handle->pipe.conn.readfile_thread = NULL;
- /* resume after it is finished */
- uv_mutex_lock(m);
- handle->pipe.conn.readfile_thread = hThread;
- uv_mutex_unlock(m);
- goto restart_readfile;
- } else {
- result = 1; /* successfully stopped reading */
+ if (handle->flags & UV_HANDLE_READING) {
+ result = ReadFile(handle->handle,
+ &uv_zero_,
+ 0,
+ &bytes,
+ NULL);
+ if (!result) {
+ err = GetLastError();
+ if (err == ERROR_OPERATION_ABORTED &&
+ handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ if (handle->flags & UV_HANDLE_READING) {
+ /* just a brief break to do something else */
+ handle->pipe.conn.readfile_thread = NULL;
+ /* resume after it is finished */
+ uv_mutex_lock(m);
+ handle->pipe.conn.readfile_thread = hThread;
+ uv_mutex_unlock(m);
+ goto restart_readfile;
+ } else {
+ result = 1; /* successfully stopped reading */
+ }
}
}
+ } else {
+ result = 1; /* successfully aborted read before it even started */
}
if (hThread) {
assert(hThread == handle->pipe.conn.readfile_thread);
@@ -1515,7 +1522,10 @@ static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error,
static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle,
int error, uv_buf_t buf) {
- if (error == ERROR_BROKEN_PIPE) {
+ if (error == ERROR_OPERATION_ABORTED) {
+ /* do nothing (equivalent to EINTR) */
+ }
+ else if (error == ERROR_BROKEN_PIPE) {
uv_pipe_read_eof(loop, handle, buf);
} else {
uv_pipe_read_error(loop, handle, error, buf);
@@ -1906,6 +1916,7 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
if (os_handle == INVALID_HANDLE_VALUE)
return UV_EBADF;
+ uv__once_init();
/* In order to avoid closing a stdio file descriptor 0-2, duplicate the
* underlying OS handle and forget about the original fd.
* We could also opt to use the original OS handle and just never close it,
@@ -1961,7 +1972,7 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
if (pipe->ipc) {
assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
- pipe->pipe.conn.ipc_pid = uv_parent_pid();
+ pipe->pipe.conn.ipc_pid = uv_os_getppid();
assert(pipe->pipe.conn.ipc_pid != -1);
}
return 0;
@@ -1979,6 +1990,7 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size)
unsigned int name_len;
int err;
+ uv__once_init();
name_info = NULL;
if (handle->handle == INVALID_HANDLE_VALUE) {
@@ -2123,3 +2135,80 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
else
return UV_TCP;
}
+
+int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
+ SID_IDENTIFIER_AUTHORITY sid_world = SECURITY_WORLD_SID_AUTHORITY;
+ PACL old_dacl, new_dacl;
+ PSECURITY_DESCRIPTOR sd;
+ EXPLICIT_ACCESS ea;
+ PSID everyone;
+ int error;
+
+ if (handle == NULL || handle->handle == INVALID_HANDLE_VALUE)
+ return UV_EBADF;
+
+ if (mode != UV_READABLE &&
+ mode != UV_WRITABLE &&
+ mode != (UV_WRITABLE | UV_READABLE))
+ return UV_EINVAL;
+
+ if (!AllocateAndInitializeSid(&sid_world,
+ 1,
+ SECURITY_WORLD_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &everyone)) {
+ error = GetLastError();
+ goto done;
+ }
+
+ if (GetSecurityInfo(handle->handle,
+ SE_KERNEL_OBJECT,
+ DACL_SECURITY_INFORMATION,
+ NULL,
+ NULL,
+ &old_dacl,
+ NULL,
+ &sd)) {
+ error = GetLastError();
+ goto clean_sid;
+ }
+
+ memset(&ea, 0, sizeof(EXPLICIT_ACCESS));
+ if (mode & UV_READABLE)
+ ea.grfAccessPermissions |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
+ if (mode & UV_WRITABLE)
+ ea.grfAccessPermissions |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
+ ea.grfAccessPermissions |= SYNCHRONIZE;
+ ea.grfAccessMode = SET_ACCESS;
+ ea.grfInheritance = NO_INHERITANCE;
+ ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
+ ea.Trustee.ptstrName = (LPTSTR)everyone;
+
+ if (SetEntriesInAcl(1, &ea, old_dacl, &new_dacl)) {
+ error = GetLastError();
+ goto clean_sd;
+ }
+
+ if (SetSecurityInfo(handle->handle,
+ SE_KERNEL_OBJECT,
+ DACL_SECURITY_INFORMATION,
+ NULL,
+ NULL,
+ new_dacl,
+ NULL)) {
+ error = GetLastError();
+ goto clean_dacl;
+ }
+
+ error = 0;
+
+clean_dacl:
+ LocalFree((HLOCAL) new_dacl);
+clean_sd:
+ LocalFree((HLOCAL) sd);
+clean_sid:
+ FreeSid(everyone);
+done:
+ return uv_translate_sys_error(error);
+}
diff --git a/Utilities/cmlibuv/src/win/process.c b/Utilities/cmlibuv/src/win/process.c
index d141601..cc06d9e 100644
--- a/Utilities/cmlibuv/src/win/process.c
+++ b/Utilities/cmlibuv/src/win/process.c
@@ -405,8 +405,15 @@ static WCHAR* search_path(const WCHAR *file,
/* Next slice starts just after where the previous one ended */
dir_start = dir_end;
+ /* If path is quoted, find quote end */
+ if (*dir_start == L'"' || *dir_start == L'\'') {
+ dir_end = wcschr(dir_start + 1, *dir_start);
+ if (dir_end == NULL) {
+ dir_end = wcschr(dir_start, L'\0');
+ }
+ }
/* Slice until the next ; or \0 is found */
- dir_end = wcschr(dir_start, L';');
+ dir_end = wcschr(dir_end, L';');
if (dir_end == NULL) {
dir_end = wcschr(dir_start, L'\0');
}
@@ -1051,15 +1058,18 @@ int uv_spawn(uv_loop_t* loop,
startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1);
startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2);
+ process_flags = CREATE_UNICODE_ENVIRONMENT;
+
if (options->flags & UV_PROCESS_WINDOWS_HIDE) {
/* Use SW_HIDE to avoid any potential process window. */
startup.wShowWindow = SW_HIDE;
+
+ /* Hide console windows. */
+ process_flags |= CREATE_NO_WINDOW;
} else {
startup.wShowWindow = SW_SHOWDEFAULT;
}
- process_flags = CREATE_UNICODE_ENVIRONMENT;
-
if (options->flags & UV_PROCESS_DETACHED) {
/* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That
* means that libuv might not let you create a fully daemonized process
@@ -1163,6 +1173,10 @@ int uv_spawn(uv_loop_t* loop,
static int uv__kill(HANDLE process_handle, int signum) {
+ if (signum < 0 || signum >= NSIG) {
+ return UV_EINVAL;
+ }
+
switch (signum) {
case SIGTERM:
case SIGKILL:
@@ -1227,8 +1241,15 @@ int uv_process_kill(uv_process_t* process, int signum) {
int uv_kill(int pid, int signum) {
int err;
- HANDLE process_handle = OpenProcess(PROCESS_TERMINATE |
- PROCESS_QUERY_INFORMATION, FALSE, pid);
+ HANDLE process_handle;
+
+ if (pid == 0) {
+ process_handle = GetCurrentProcess();
+ } else {
+ process_handle = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION,
+ FALSE,
+ pid);
+ }
if (process_handle == NULL) {
err = GetLastError();
diff --git a/Utilities/cmlibuv/src/win/signal.c b/Utilities/cmlibuv/src/win/signal.c
index 7b42dd9..a174da1 100644
--- a/Utilities/cmlibuv/src/win/signal.c
+++ b/Utilities/cmlibuv/src/win/signal.c
@@ -64,7 +64,7 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
}
-RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare);
+RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare)
/*
diff --git a/Utilities/cmlibuv/src/win/stream-inl.h b/Utilities/cmlibuv/src/win/stream-inl.h
index bf12148..dba0374 100644
--- a/Utilities/cmlibuv/src/win/stream-inl.h
+++ b/Utilities/cmlibuv/src/win/stream-inl.h
@@ -36,6 +36,7 @@ INLINE static void uv_stream_init(uv_loop_t* loop,
uv__handle_init(loop, (uv_handle_t*) handle, type);
handle->write_queue_size = 0;
handle->activecnt = 0;
+ handle->stream.conn.shutdown_req = NULL;
}
@@ -47,8 +48,6 @@ INLINE static void uv_connection_init(uv_stream_t* handle) {
handle->read_req.event_handle = NULL;
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
handle->read_req.data = handle;
-
- handle->stream.conn.shutdown_req = NULL;
}
diff --git a/Utilities/cmlibuv/src/win/tcp.c b/Utilities/cmlibuv/src/win/tcp.c
index 972539f..fd6efba 100644
--- a/Utilities/cmlibuv/src/win/tcp.c
+++ b/Utilities/cmlibuv/src/win/tcp.c
@@ -747,10 +747,15 @@ static int uv_tcp_try_connect(uv_connect_t* req,
uv_connect_cb cb) {
uv_loop_t* loop = handle->loop;
const struct sockaddr* bind_addr;
+ struct sockaddr_storage converted;
BOOL success;
DWORD bytes;
int err;
+ err = uv__convert_to_localhost_if_unspecified(addr, &converted);
+ if (err)
+ return err;
+
if (handle->delayed_error) {
return handle->delayed_error;
}
@@ -782,12 +787,12 @@ static int uv_tcp_try_connect(uv_connect_t* req,
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
success = handle->tcp.conn.func_connectex(handle->socket,
- addr,
- addrlen,
- NULL,
- 0,
- &bytes,
- &req->u.io.overlapped);
+ (const struct sockaddr*) &converted,
+ addrlen,
+ NULL,
+ 0,
+ &bytes,
+ &req->u.io.overlapped);
if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
/* Process the req without IOCP. */
@@ -1446,6 +1451,8 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
WSAPROTOCOL_INFOW protocol_info;
int opt_len;
int err;
+ struct sockaddr_storage saddr;
+ int saddr_len;
/* Detect the address family of the socket. */
opt_len = (int) sizeof protocol_info;
@@ -1466,6 +1473,19 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
return uv_translate_sys_error(err);
}
+ /* Support already active socket. */
+ saddr_len = sizeof(saddr);
+ if (!uv_tcp_getsockname(handle, (struct sockaddr*) &saddr, &saddr_len)) {
+ /* Socket is already bound. */
+ handle->flags |= UV_HANDLE_BOUND;
+ saddr_len = sizeof(saddr);
+ if (!uv_tcp_getpeername(handle, (struct sockaddr*) &saddr, &saddr_len)) {
+ /* Socket is already connected. */
+ uv_connection_init((uv_stream_t*) handle);
+ handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ }
+ }
+
return 0;
}
diff --git a/Utilities/cmlibuv/src/win/thread.c b/Utilities/cmlibuv/src/win/thread.c
index 91684e9..9eaad77 100644
--- a/Utilities/cmlibuv/src/win/thread.c
+++ b/Utilities/cmlibuv/src/win/thread.c
@@ -182,6 +182,7 @@ int uv_thread_join(uv_thread_t *tid) {
else {
CloseHandle(*tid);
*tid = 0;
+ MemoryBarrier(); /* For feature parity with pthread_join(). */
return 0;
}
}
@@ -198,6 +199,11 @@ int uv_mutex_init(uv_mutex_t* mutex) {
}
+int uv_mutex_init_recursive(uv_mutex_t* mutex) {
+ return uv_mutex_init(mutex);
+}
+
+
void uv_mutex_destroy(uv_mutex_t* mutex) {
DeleteCriticalSection(mutex);
}
diff --git a/Utilities/cmlibuv/src/win/timer.c b/Utilities/cmlibuv/src/win/timer.c
index 27ca771..7e006fe 100644
--- a/Utilities/cmlibuv/src/win/timer.c
+++ b/Utilities/cmlibuv/src/win/timer.c
@@ -56,7 +56,7 @@ static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) {
}
-RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare);
+RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare)
int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
diff --git a/Utilities/cmlibuv/src/win/tty.c b/Utilities/cmlibuv/src/win/tty.c
index a6f5839..05a11e8 100644
--- a/Utilities/cmlibuv/src/win/tty.c
+++ b/Utilities/cmlibuv/src/win/tty.c
@@ -112,14 +112,30 @@ static int uv_tty_virtual_offset = -1;
static int uv_tty_virtual_height = -1;
static int uv_tty_virtual_width = -1;
+/* The console window size
+ * We keep this separate from uv_tty_virtual_*. We use those values to only
+ * handle signalling SIGWINCH
+ */
+
+static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE;
+static int uv__tty_console_height = -1;
+static int uv__tty_console_width = -1;
+
+static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param);
+static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
+ DWORD event,
+ HWND hwnd,
+ LONG idObject,
+ LONG idChild,
+ DWORD dwEventThread,
+ DWORD dwmsEventTime);
+
/* We use a semaphore rather than a mutex or critical section because in some
cases (uv__cancel_read_console) we need take the lock in the main thread and
release it in another thread. Using a semaphore ensures that in such
scenario the main thread will still block when trying to acquire the lock. */
static uv_sem_t uv_tty_output_lock;
-static HANDLE uv_tty_output_handle = INVALID_HANDLE_VALUE;
-
static WORD uv_tty_default_text_attributes =
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
@@ -141,6 +157,18 @@ static void uv__determine_vterm_state(HANDLE handle);
void uv_console_init(void) {
if (uv_sem_init(&uv_tty_output_lock, 1))
abort();
+ uv__tty_console_handle = CreateFileW(L"CONOUT$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_WRITE,
+ 0,
+ OPEN_EXISTING,
+ 0,
+ 0);
+ if (uv__tty_console_handle != NULL) {
+ QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
+ NULL,
+ WT_EXECUTELONGFUNCTION);
+ }
}
@@ -148,6 +176,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
HANDLE handle;
CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
+ uv__once_init();
handle = (HANDLE) uv__get_osfhandle(fd);
if (handle == INVALID_HANDLE_VALUE)
return UV_EBADF;
@@ -183,11 +212,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
if (uv__vterm_state == UV_UNCHECKED)
uv__determine_vterm_state(handle);
- /* Store the global tty output handle. This handle is used by TTY read */
- /* streams to update the virtual window when a CONSOLE_BUFFER_SIZE_EVENT */
- /* is received. */
- uv_tty_output_handle = handle;
-
/* Remember the original console text attributes. */
uv_tty_capture_initial_style(&screen_buffer_info);
@@ -704,25 +728,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
}
records_left--;
- /* If the window was resized, recompute the virtual window size. This */
- /* will trigger a SIGWINCH signal if the window size changed in an */
- /* way that matters to libuv. */
- if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
- CONSOLE_SCREEN_BUFFER_INFO info;
-
- uv_sem_wait(&uv_tty_output_lock);
-
- if (uv_tty_output_handle != INVALID_HANDLE_VALUE &&
- GetConsoleScreenBufferInfo(uv_tty_output_handle, &info)) {
- uv_tty_update_virtual_window(&info);
- }
-
- uv_sem_post(&uv_tty_output_lock);
-
- continue;
- }
-
- /* Ignore other events that are not key or resize events. */
+ /* Ignore other events that are not key events. */
if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) {
continue;
}
@@ -1102,9 +1108,6 @@ static int uv__cancel_read_console(uv_tty_t* handle) {
static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
- int old_virtual_width = uv_tty_virtual_width;
- int old_virtual_height = uv_tty_virtual_height;
-
uv_tty_virtual_width = info->dwSize.X;
uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1;
@@ -1124,14 +1127,6 @@ static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
if (uv_tty_virtual_offset < 0) {
uv_tty_virtual_offset = 0;
}
-
- /* If the virtual window size changed, emit a SIGWINCH signal. Don't emit */
- /* if this was the first time the virtual window size was computed. */
- if (old_virtual_width != -1 && old_virtual_height != -1 &&
- (uv_tty_virtual_width != old_virtual_width ||
- uv_tty_virtual_height != old_virtual_height)) {
- uv__signal_dispatch(SIGWINCH);
- }
}
@@ -2279,3 +2274,55 @@ static void uv__determine_vterm_state(HANDLE handle) {
uv__vterm_state = UV_SUPPORTED;
}
+
+static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) {
+ CONSOLE_SCREEN_BUFFER_INFO sb_info;
+ MSG msg;
+
+ if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info))
+ return 0;
+
+ uv__tty_console_width = sb_info.dwSize.X;
+ uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
+
+ if (pSetWinEventHook == NULL)
+ return 0;
+
+ if (!pSetWinEventHook(EVENT_CONSOLE_LAYOUT,
+ EVENT_CONSOLE_LAYOUT,
+ NULL,
+ uv__tty_console_resize_event,
+ 0,
+ 0,
+ WINEVENT_OUTOFCONTEXT))
+ return 0;
+
+ while (GetMessage(&msg, NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ return 0;
+}
+
+static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
+ DWORD event,
+ HWND hwnd,
+ LONG idObject,
+ LONG idChild,
+ DWORD dwEventThread,
+ DWORD dwmsEventTime) {
+ CONSOLE_SCREEN_BUFFER_INFO sb_info;
+ int width, height;
+
+ if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info))
+ return;
+
+ width = sb_info.dwSize.X;
+ height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
+
+ if (width != uv__tty_console_width || height != uv__tty_console_height) {
+ uv__tty_console_width = width;
+ uv__tty_console_height = height;
+ uv__signal_dispatch(SIGWINCH);
+ }
+}
diff --git a/Utilities/cmlibuv/src/win/udp.c b/Utilities/cmlibuv/src/win/udp.c
index 2fd15cf..cd1d0e0 100644
--- a/Utilities/cmlibuv/src/win/udp.c
+++ b/Utilities/cmlibuv/src/win/udp.c
@@ -897,13 +897,12 @@ int uv__udp_send(uv_udp_send_t* req,
int err;
if (!(handle->flags & UV_HANDLE_BOUND)) {
- if (addrlen == sizeof(uv_addr_ip4_any_)) {
+ if (addrlen == sizeof(uv_addr_ip4_any_))
bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
- } else if (addrlen == sizeof(uv_addr_ip6_any_)) {
+ else if (addrlen == sizeof(uv_addr_ip6_any_))
bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
- } else {
- abort();
- }
+ else
+ return UV_EINVAL;
err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
if (err)
return uv_translate_sys_error(err);
@@ -922,5 +921,45 @@ int uv__udp_try_send(uv_udp_t* handle,
unsigned int nbufs,
const struct sockaddr* addr,
unsigned int addrlen) {
- return UV_ENOSYS;
+ DWORD bytes;
+ const struct sockaddr* bind_addr;
+ struct sockaddr_storage converted;
+ int err;
+
+ assert(nbufs > 0);
+
+ err = uv__convert_to_localhost_if_unspecified(addr, &converted);
+ if (err)
+ return err;
+
+ /* Already sending a message.*/
+ if (handle->send_queue_count != 0)
+ return UV_EAGAIN;
+
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ if (addrlen == sizeof(uv_addr_ip4_any_))
+ bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
+ else if (addrlen == sizeof(uv_addr_ip6_any_))
+ bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
+ else
+ return UV_EINVAL;
+ err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
+ if (err)
+ return uv_translate_sys_error(err);
+ }
+
+ err = WSASendTo(handle->socket,
+ (WSABUF*)bufs,
+ nbufs,
+ &bytes,
+ 0,
+ (const struct sockaddr*) &converted,
+ addrlen,
+ NULL,
+ NULL);
+
+ if (err)
+ return uv_translate_sys_error(WSAGetLastError());
+
+ return bytes;
}
diff --git a/Utilities/cmlibuv/src/win/util.c b/Utilities/cmlibuv/src/win/util.c
index d2e7f77..3100bc2 100644
--- a/Utilities/cmlibuv/src/win/util.c
+++ b/Utilities/cmlibuv/src/win/util.c
@@ -331,7 +331,12 @@ uint64_t uv_get_total_memory(void) {
}
-int uv_parent_pid(void) {
+uv_pid_t uv_os_getpid(void) {
+ return GetCurrentProcessId();
+}
+
+
+uv_pid_t uv_os_getppid(void) {
int parent_pid = -1;
HANDLE handle;
PROCESSENTRY32 pe;
@@ -1388,7 +1393,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
return uv_translate_sys_error(GetLastError());
- bufsize = sizeof(path);
+ bufsize = ARRAY_SIZE(path);
if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
r = GetLastError();
CloseHandle(token);
@@ -1403,7 +1408,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
CloseHandle(token);
/* Get the username using GetUserNameW() */
- bufsize = sizeof(username);
+ bufsize = ARRAY_SIZE(username);
if (!GetUserNameW(username, &bufsize)) {
r = GetLastError();
diff --git a/Utilities/cmlibuv/src/win/winapi.c b/Utilities/cmlibuv/src/win/winapi.c
index aa5d719..4ccdf0a 100644
--- a/Utilities/cmlibuv/src/win/winapi.c
+++ b/Utilities/cmlibuv/src/win/winapi.c
@@ -52,11 +52,15 @@ sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
/* Powrprof.dll function pointer */
sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
+/* User32.dll function pointer */
+sSetWinEventHook pSetWinEventHook;
+
void uv_winapi_init(void) {
HMODULE ntdll_module;
HMODULE kernel32_module;
HMODULE powrprof_module;
+ HMODULE user32_module;
ntdll_module = GetModuleHandleA("ntdll.dll");
if (ntdll_module == NULL) {
@@ -156,4 +160,10 @@ void uv_winapi_init(void) {
GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification");
}
+ user32_module = LoadLibraryA("user32.dll");
+ if (user32_module != NULL) {
+ pSetWinEventHook = (sSetWinEventHook)
+ GetProcAddress(user32_module, "SetWinEventHook");
+ }
+
}
diff --git a/Utilities/cmlibuv/src/win/winapi.h b/Utilities/cmlibuv/src/win/winapi.h
index 4b0eeca..8993c65 100644
--- a/Utilities/cmlibuv/src/win/winapi.h
+++ b/Utilities/cmlibuv/src/win/winapi.h
@@ -4104,6 +4104,10 @@
# define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000
#endif
+#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
+# define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x00000002
+#endif
+
/* from winternl.h */
typedef struct _UNICODE_STRING {
USHORT Length;
@@ -4730,6 +4734,25 @@ typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification)
HANDLE Recipient,
_PHPOWERNOTIFY RegistrationHandle);
+/* from Winuser.h */
+typedef VOID (CALLBACK* WINEVENTPROC)
+ (HWINEVENTHOOK hWinEventHook,
+ DWORD event,
+ HWND hwnd,
+ LONG idObject,
+ LONG idChild,
+ DWORD idEventThread,
+ DWORD dwmsEventTime);
+
+typedef HWINEVENTHOOK (WINAPI *sSetWinEventHook)
+ (UINT eventMin,
+ UINT eventMax,
+ HMODULE hmodWinEventProc,
+ WINEVENTPROC lpfnWinEventProc,
+ DWORD idProcess,
+ DWORD idThread,
+ UINT dwflags);
+
/* Ntdll function pointers */
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
@@ -4758,4 +4781,7 @@ extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
/* Powrprof.dll function pointer */
extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
+/* User32.dll function pointer */
+extern sSetWinEventHook pSetWinEventHook;
+
#endif /* UV_WIN_WINAPI_H_ */
diff --git a/Utilities/cmlibuv/src/win/winsock.c b/Utilities/cmlibuv/src/win/winsock.c
index e86d76b..7cfa90f 100644
--- a/Utilities/cmlibuv/src/win/winsock.c
+++ b/Utilities/cmlibuv/src/win/winsock.c
@@ -559,3 +559,31 @@ int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
return SOCKET_ERROR;
}
}
+
+int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr,
+ struct sockaddr_storage* storage) {
+ struct sockaddr_in* dest4;
+ struct sockaddr_in6* dest6;
+
+ if (addr == NULL)
+ return UV_EINVAL;
+
+ switch (addr->sa_family) {
+ case AF_INET:
+ dest4 = (struct sockaddr_in*) storage;
+ memcpy(dest4, addr, sizeof(*dest4));
+ if (dest4->sin_addr.s_addr == 0)
+ dest4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ return 0;
+ case AF_INET6:
+ dest6 = (struct sockaddr_in6*) storage;
+ memcpy(dest6, addr, sizeof(*dest6));
+ if (memcmp(&dest6->sin6_addr,
+ &uv_addr_ip6_any_.sin6_addr,
+ sizeof(uv_addr_ip6_any_.sin6_addr)) == 0)
+ dest6->sin6_addr = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
+ return 0;
+ default:
+ return UV_EINVAL;
+ }
+}
diff --git a/Utilities/cmlibuv/src/win/winsock.h b/Utilities/cmlibuv/src/win/winsock.h
index 3115fe3..e8b274e 100644
--- a/Utilities/cmlibuv/src/win/winsock.h
+++ b/Utilities/cmlibuv/src/win/winsock.h
@@ -188,4 +188,7 @@ typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH {
#endif
+int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr,
+ struct sockaddr_storage* storage);
+
#endif /* UV_WIN_WINSOCK_H_ */