├── .gitignore
├── CMakeLists.txt
├── LICENSE.GPL
├── README
├── bin
├── ibjom.bat
├── xgejom.bat
└── xgejom.xml
├── changelog.txt
├── dist
└── createDistZip.pl
├── jom.pro
├── src
├── app
│ ├── CMakeLists.txt
│ ├── app.pro
│ ├── app.qrc
│ ├── app.rc.in
│ ├── application.cpp
│ ├── application.h
│ ├── main.cpp
│ ├── qt.conf
│ └── version.txt
└── jomlib
│ ├── CMakeLists.txt
│ ├── commandexecutor.cpp
│ ├── commandexecutor.h
│ ├── dependencygraph.cpp
│ ├── dependencygraph.h
│ ├── exception.cpp
│ ├── exception.h
│ ├── fastfileinfo.cpp
│ ├── fastfileinfo.h
│ ├── filetime.cpp
│ ├── filetime.h
│ ├── helperfunctions.cpp
│ ├── helperfunctions.h
│ ├── iocompletionport.cpp
│ ├── iocompletionport.h
│ ├── jobclient.cpp
│ ├── jobclient.h
│ ├── jobclientacquirehelper.cpp
│ ├── jobclientacquirehelper.h
│ ├── jobserver.cpp
│ ├── jobserver.h
│ ├── jomlib.pro
│ ├── jomprocess.cpp
│ ├── jomprocess.h
│ ├── jomprocess_qt.cpp
│ ├── macrotable.cpp
│ ├── macrotable.h
│ ├── makefile.cpp
│ ├── makefile.h
│ ├── makefilefactory.cpp
│ ├── makefilefactory.h
│ ├── makefilelinereader.cpp
│ ├── makefilelinereader.h
│ ├── options.cpp
│ ├── options.h
│ ├── parser.cpp
│ ├── parser.h
│ ├── ppexpr-lex.inc
│ ├── ppexpr.g
│ ├── ppexpr.l
│ ├── ppexpr_grammar.cpp
│ ├── ppexpr_grammar_p.h
│ ├── ppexprparser.cpp
│ ├── ppexprparser.h
│ ├── preprocessor.cpp
│ ├── preprocessor.h
│ ├── processenvironment.h
│ ├── stable.h
│ ├── targetexecutor.cpp
│ ├── targetexecutor.h
│ └── use_jomlib.pri
└── tests
├── CMakeLists.txt
├── makefiles
├── blackbox
│ ├── buildUnrelatedTargetsOnError
│ │ └── test.mk
│ ├── builtins
│ │ └── cd.mk
│ ├── caseInsensitiveDependents
│ │ └── test.mk
│ ├── environmentVariables
│ │ └── test.mk
│ ├── environmentVariablesCaseInsensitivity
│ │ └── test.mk
│ ├── environmentVariablesInCommands
│ │ └── test.mk
│ ├── ignoreExitCodes
│ │ └── test.mk
│ ├── inlineFiles
│ │ ├── test.mk
│ │ ├── test_basic_expected.txt
│ │ ├── test_escaping_expected.txt
│ │ └── test_multipleFiles_expected.txt
│ ├── macrosOnCommandLine
│ │ └── test.mk
│ ├── noTargets
│ │ └── test.mk
│ ├── nonexistentdependent
│ │ └── test.mk
│ ├── outofdatecheck
│ │ └── test.mk
│ ├── suffixes
│ │ ├── one.a
│ │ ├── one.b
│ │ ├── one.c
│ │ ├── test.mk
│ │ ├── three.c
│ │ ├── three.d
│ │ ├── two.b
│ │ └── two.c
│ └── unicodeFiles
│ │ ├── test_utf16.mk
│ │ └── test_utf8.mk
├── circular_include.mk
├── circular_include2.mk
├── commandmodifiers.mk
├── comments.mk
├── conditionals.mk
├── cycle_in_targets.mk
├── depswithspace.mk
├── descriptionblocks.mk
├── dotdirectives.mk
├── file#99.txt
├── fileNameMacrosInDependents.mk
├── filenamemacros.mk
├── foo1.cpp
├── foo3.cpp
├── foo4.cpp
├── include1.mk
├── include2.mk
├── include5.mk
├── include_test.mk
├── infrules.mk
├── macrotest.mk
├── subdir
│ ├── foo1.cpp
│ ├── foo2.cpp
│ ├── foo4.cpp
│ ├── include3.mk
│ ├── include4.mk
│ ├── include7.mk
│ ├── include8.mk
│ ├── include9.mk
│ └── subsub
│ │ └── include6.mk
├── targetmultidef.mk
├── wildcardsInDependencies.mk
└── windowspaths.mk
├── tests.cpp
├── tests.h
└── tests.pro
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | tmp
3 | debug
4 | release
5 | Makefile
6 | Makefile.Debug
7 | Makefile.Release
8 | *.pro.user*
9 | *.lib
10 | *.obj
11 | *.ncb
12 | *.sln
13 | *.suo
14 | *.vcproj*
15 | *.pdb
16 | *.idb
17 | *.ib_pdb_index
18 | *.bak
19 | *.swp
20 | *~
21 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.6)
2 | project(jom LANGUAGES CXX)
3 |
4 | set(CMAKE_AUTOMOC ON)
5 | enable_testing()
6 |
7 | # where to look first for cmake modules
8 | set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules;${CMAKE_MODULE_PATH}")
9 |
10 | find_package(Qt5 5.2.0 REQUIRED COMPONENTS Core)
11 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
12 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
13 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
14 | add_subdirectory(src/jomlib)
15 | add_subdirectory(src/app)
16 |
17 | if(BUILD_TESTING)
18 | add_subdirectory(tests)
19 | endif()
20 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | jom - the parallel make tool for Windows
2 |
3 | It's aimed to be an nmake clone with support for parallel builds.
4 | The project's wiki is here: http://wiki.qt.io/Jom
5 |
6 | == How to compile jom ==
7 | Jom is a Qt program. The steps to compile jom on command line are:
8 | qmake
9 | nmake
10 |
11 | == How to compile jom with cmake ==
12 | We assume that everything we do happens in the folder X:\build-jom
13 | 1. unpack these sources of jom into X:\build-jom\jom
14 | 2. add a build directory somewhere - this normally either is a
15 | directory on the same level as the build directory
16 | or a subdirectory of the source root directory.
17 | !!! Do not try to build from within the source directory !!!
18 | 3. switch into the build directory and run the following commands:
19 |
20 | X:\build-jom\build> cmake X:\build-jom\jom -G "NMake Makefiles" -DCMAKE_PREFIX_PATH=X:\build-jom -DCMAKE_INSTALL_PREFIX=X:\build-jom\install
21 | ...
22 |
23 | To take a special version of Qt, append -DQT_QMAKE_EXECUTABLE:PATH=X:\build-jom\qt\bin\qmake.exe .
24 |
25 | Now just run:
26 |
27 | X:\build-jom\build> nmake && nmake install
28 | ...
29 |
30 | If you want to begin new, just throw away the build dir.
31 |
32 | == Running the tests ==
33 | To build the unit tests in jom, add the option -DJOM_ENABLE_TESTS=ON
34 | to the cmake line.
35 | To run the tests, you can simply type
36 |
37 | X:\build-jom\> nmake test
38 | ...
39 |
40 | == Environment variables ==
41 |
42 | Like nmake, jom reads default command line arguments from an environment variable: JOMFLAGS.
43 | If JOMFLAGS is not set, MAKEFLAGS is read.
44 | This is useful to set up separate flags for nmake and jom, e.g.
45 | set MAKEFLAGS=L
46 | set JOMFLAGS=Lj8
47 |
48 | == .SYNC dependents ==
49 |
50 | You can use the .SYNC directive on the right side of a description
51 | block definition T to prevent jom from running all of T's dependents
52 | in parallel.
53 | For example the following description block adds further dependencies
54 | between its dependents.
55 |
56 | all: Init Prebuild .SYNC Build .SYNC Postbuild
57 |
58 | This adds these additional dependencies:
59 | Build -> Init Prebuild
60 | Postbuild -> Build
61 |
62 | Now the 'Init' and 'Prebuild' targets are built before 'Build'.
63 |
64 |
--------------------------------------------------------------------------------
/bin/ibjom.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | setlocal enabledelayedexpansion
3 | if "%IBJOM_NUMBEROFJOBS%" == "" set IBJOM_NUMBEROFJOBS=20
4 | BuildConsole /command="jom -j%IBJOM_NUMBEROFJOBS% %*" || exit /b !ERRORLEVEL!
5 | endlocal
6 |
--------------------------------------------------------------------------------
/bin/xgejom.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | setlocal enabledelayedexpansion
3 | if "%IBJOM_NUMBEROFJOBS%" == "" set IBJOM_NUMBEROFJOBS=60
4 | set NINJAFLAGS=-j60
5 | xgConsole /profile="%~dp0\xgejom.xml" /command="jom -j%IBJOM_NUMBEROFJOBS% %*" || exit /b !ERRORLEVEL!
6 | endlocal
7 |
--------------------------------------------------------------------------------
/bin/xgejom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/changelog.txt:
--------------------------------------------------------------------------------
1 | This is the changelog for jom 1.1.4, the parallel make tool.
2 |
3 | Changes since jom 1.1.3
4 | - Fixed handling of the command line option /j.
5 | - Makefiles that do not contain targets are allowed.
6 | - Fixed handling of macro definitions on the command line (QTCREATORBUG-22176).
7 | - Enabled usage of paths longer than MAX_PATH (QTCREATORBUG-22848).
8 | - Added version information to the executable (QTCREATORBUG-23290).
9 | - Fixed directory separators in the MAKEDIR variable (QTCREATORBUG-23559).
10 | - Fixed expansion of absolute path wildcard dependencies (QTCREATORBUG-26745).
11 | - Fixed performance penalty when checking for dependency cycles in complex
12 | Makefiles (QTCREATORBUG-29412).
13 |
14 | Changes since jom 1.1.2
15 | - Removed the /KEEPTEMPFILES option. This option only worked for top-level make
16 | files anyway and was less useful than intended. Use the /U option to display
17 | the content of inline files instead.
18 | - Fixed an issue where jom.exe would try to load qt.conf from drive E.
19 | - Fixed handling of double backslash at the end of line (QTCREATORBUG-20550).
20 | - Fixed handling of line continuations in preprocessor directives
21 | (QTCREATORBUG-8621, QTCREATORBUG-18001).
22 | - Fixed the CMake project file.
23 |
24 | Changes since jom 1.1.1
25 | - Fixed exit code propagation in xgejom.bat and ibjom.bat (QTCREATORBUG-16619).
26 | - Updated the CMake build system to use Qt5.
27 | - Fixed bogus path in error message for failed targets.
28 | - Fixed error "JobClient destroyed while still acquiring." that could be yielded
29 | for failed builds.
30 | - Fixed /k option (QTCREATORBUG-17131).
31 | - Fixed sub-jom detection for chocolatey shims (QTCREATORBUG-15494).
32 |
33 | Changes since jom 1.1.0
34 | - Added the special .NOTPARALLEL target that disables parallel build for the
35 | containing makefile.
36 | - Fixed glitches in !include directives. Includes like <"foo.mk"> were not
37 | possible. Includes like "foo.mk" did not recursively search through parent
38 | makefiles directories.
39 | - Introduced the JOMFLAGS environment variable. This is a MAKEFLAGS pendant.
40 | JOMFLAGS is useful to set up separate flags for nmake and jom.
41 | - Renamed ibjom.cmd to ibjom.bat for consistency.
42 | - Added xgejom.bat, a wrapper for the IncrediBuild XGE interface.
43 | - Fixed wildcard handling for subdirectories (QTCREATORBUG-16499).
44 | - Implemented the "build all targets" option (QTCREATORBUG-16500).
45 |
46 | Changes since jom 1.0.16
47 | - Restrict the number of parallel jobs in recursively called instances
48 | similar to GNU make's jobserver (QTCREATORBUG-10846).
49 |
50 | Changes since jom 1.0.15
51 | - Fix occasional hang on exit (QTCREATORBUG-14600).
52 |
53 | Changes since jom 1.0.14
54 | - Fix potential hang on error in a sub-jom.
55 | - Yield error on missing !endif directives (QTCREATORBUG-14211).
56 | - Fix ignoring exit codes greater than 255.
57 | - Fix /DUMPGRAPHDOT option (QTCREATORBUG-14004).
58 | - Fix $? filename macro for nonexistent targets (QTCREATORBUG-14125).
59 | - Fix quoting of dependencies with spaces (QTCREATORBUG-12296).
60 |
61 | Changes since jom 1.0.13
62 | - Fix exit code forwarding. (QTCREATORBUG-11556)
63 | - Fix file name macro modifers for $** and $?. (QTCREATORBUG-6932)
64 | - Fix equal signs in semicolon command syntax. (QTCREATORBUG-7942)
65 | - Fix error line numbers for inline files. (QTCREATORBUG-8451)
66 | - Ignore macro assignments in inline files. (QTCREATORBUG-8452)
67 | - Yield error on unexpected !ENDIF directive.
68 | - Support wildcards in dependency lines. (QTCREATORBUG-10439)
69 | - Use IcrediBuild's BuildConsole instead of the XGE interface in ibjom.
70 |
71 | Changes since jom 1.0.12
72 | - Fix spurious "Can't start command" error.
73 | - Fix passing of -j argument to subjoms.
74 | - Sanity check the -j argument.
75 | - Fix regression of non-functional set command in command blocks.
76 | - Fix handling of environment variables that would cause a syntax errors in
77 | makefiles.
78 | - Fix handling of environment variables with lowercase names.
79 |
80 | Changes since jom 1.0.11
81 | - Performance improvements.
82 | - Fixed whitespace in command line arguments. (QTCREATORBUG-7428)
83 | - Enhanced responsiveness of subjom output.
84 | - Separate output of stdout and stderr.
85 | - Fix the output of silent commands in /n mode. (QTCREATORBUG-7170)
86 | - Implemented the /U switch for dumping inline files.
87 | - Fix expansion of environment variables.
88 |
89 | Changes since jom 1.0.10
90 | - Fix exit code for /k command line switch. (QTCREATORBUG-6987)
91 | - Fix spurious 0x0d characters in process output. (QTCREATORBUG-6986)
92 | - Fix process output ordering and printing of large amounts of output
93 | in recursive jom scenarios.
94 | - Improved performance by caching file time stamps.
95 |
96 | Changes since jom 1.0.9
97 | - Fix regression that caused jom to fail on Windows XP.
98 |
99 | Changes since jom 1.0.8
100 | - The GNU Make option -w is now supported to print the current working
101 | directory before and after other processing.
102 | - Fix crash when specifying a target for an empty makefile.
103 | (QTCREATORBUG-6552)
104 | - Fix lookup for targets in the Makefile's directory. (QTCREATORBUG-6546)
105 | - Fix handling of environment variables. (QTCREATORBUG-6578)
106 | - Specifying an exit code with the '-' command modifier was fixed.
107 | - Fix command modifiers in inference rules. (QTCREATORBUG-6742)
108 | - Fix parsing of the "ignore exit code" command modifier.
109 | - Fix (very rare) deadlock and zombie processes.
110 | - The preprocessor directive !include now looks up files in the
111 | include directories correctly. (QTCREATORBUG-6869)
112 |
113 | Changes since jom 1.0.7
114 | - Fix spawning of child processes that expect a valid stdin handle.
115 | E.g. xcopy couldn't be called anymore.
116 | - CMakeList.txt was fixed (thanks to Ryan Pavlik).
117 |
118 | Changes since jom 1.0.6
119 | - Fix blank lines in output. (QTCREATORBUG-3974)
120 | - Small performance improvement due to compilation with
121 | QT_USE_FAST_CONCATENATION and QT_USE_FAST_OPERATOR_PLUS.
122 | - Ctrl-C handling has been revisited. Much simpler and more correct.
123 | Before the compiler jobs didn't get a Ctrl-C but were terminated.
124 | - Special .SYNC dependents implemented. See README for a small description.
125 | (QTCREATORBUG-3257)
126 | - Handle quoted dollar signs in inline files correctly. (QTCREATORBUG-2875)
127 | - Respect the MAKEFLAGS environment variable. (QTCREATORBUG-5028)
128 | - Complete detection of cmd builtins. This fixes annoying warnings when building
129 | with IncrediBuild.
130 |
131 | Changes since jom 1.0.5
132 | - Fix mean monster spawn issue.
133 |
134 | Changes since jom 1.0.4
135 | - Fix out of date check for pseudotargets. (QTCREATORBUG-3909)
136 |
137 | Changes since jom 1.0.3
138 | - Fix that -j1 wasn't passed to sub jom calls. (QTCREATORBUG-3729)
139 | - /KEEPTEMPFILES was added for debugging purposes. (QTCREATORBUG-3852)
140 | - Performance boost for incremental builds.
141 | - Improved Ctrl-C handling for recursive make.
142 |
143 | Changes since jom 1.0.2
144 | - Support variable names with underscores. (QTCREATORBUG-3235)
145 | - Keep order of dependencies on build. This is important for makefiles
146 | lacking complete dependencies. These might fail in parallel builds
147 | otherwise.
148 | - Fix issues wrt environment variables. (QTCREATORBUG-3108)
149 |
150 | Changes since jom 1.0.1
151 | - Make target names case insensitive. (QTCREATORBUG-3037)
152 | - Fix reading of include files without newline at the end.
153 | (QTBUG-15021)
154 | - Repair the cmake project file for jom.
155 |
156 | Changes since jom 1.0.0
157 | - Cleaner and faster determination of targets that must be built.
158 | - Fix incomplete up-to-date check for inference rule targets.
159 | (QTCREATORBUG-2713)
160 | - Don't filter comments in inline files. (QTCREATORBUG-2874)
161 |
162 | Changes since jom 0.9.4
163 | - Inference rule batch mode implemented.
164 | This improves performance for makefiles that make heavy use of the batch
165 | mode, e.g. qmake generated makefiles.
166 | - Improved command execution. No more batch file writing.
167 | - Macro substitution implemented. Macro expansions like
168 | $(TARGET:suffix=d) are now possible.
169 | - .SUFFIXES content is handled properly.
170 | - Fixed several bugs in file name macro expansion.
171 | - Output of concurrent processes is explicitely separated.
172 |
173 | Changes since jom 0.9.3
174 | - Opening files from volume mounted to NTFS directory fixed.
175 | (QTCREATORBUG-1475)
176 | - Output buffering issue fixed. (QTBUG-10798)
177 |
178 | Changes since jom 0.9.2
179 | - Support for multiple inline files per command line added.
180 | - Its now possible to use "." as target name. (QTCREATORBUG-1131)
181 | - Support file name macros in the file name part of inline file defitions.
182 | (QTCREATORBUG-1136)
183 | - Multiple file name macros per command line are possible now.
184 | - Single name macro invocation was added.
185 | They can be invoked like this: $A instead of $(A).
186 | - Several bugs related to file name macros have been fixed.
187 | - Handle quoted arguments from command files correctly.
188 |
189 | Changes since jom 0.9.1
190 | - Fixed conditionals in preprocessor expressions. (QTCREATORBUG-1091)
191 | - Improved parser error messages. Now we see the file, in which the
192 | error occurred. (QTCREATORBUG-1114)
193 |
194 | Changes since jom 0.9.0
195 | - Having too many rules for a target is now a warning and not an error.
196 | - Fixed several bugs in the preprocessor expression parser, e.g.
197 | QTCREATORBUG-1056.
198 |
199 | Changes since jom 0.8.9
200 | - Reset the ERRORLEVEL to zero, if command's exit code should be ignored.
201 | (QTCREATORBUG-837)
202 | - Command files can be used to pass command line options to jom.
203 | Usage: jom @commands.txt
204 | - ANTLR isn't used anymore. We're using QLALR to generate the parser for
205 | preprocessor expressions now. This makes building jom much easier.
206 |
207 |
--------------------------------------------------------------------------------
/dist/createDistZip.pl:
--------------------------------------------------------------------------------
1 | #!/bin/perl
2 | $jomVersion = `../bin/jom.exe /VERSION`;
3 | $jomVersion = substr($jomVersion, 12);
4 | $jomVersion = substr($jomVersion, 0, -1);
5 | $jomVersion =~ /(\d+)\.(\d+)\.(\d+)/;
6 | $jomVersion = ${1} . "_" . ${2} . "_" . ${3};
7 | system("copy /Y jom.zip jom_" . $jomVersion . ".zip");
8 |
--------------------------------------------------------------------------------
/jom.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = subdirs
2 | sub_jomlib.subdir = src/jomlib
3 | sub_app.subdir = src/app
4 | sub_app.depends = sub_jomlib
5 | sub_tests.subdir = tests
6 | sub_tests.depends = sub_jomlib sub_app
7 | SUBDIRS = sub_app sub_jomlib sub_tests
8 |
9 | OTHER_FILES = \
10 | changelog.txt \
11 | LICENSE.GPL \
12 | README
13 |
14 | defineTest(minQtVersion) {
15 | maj = $$1
16 | min = $$2
17 | patch = $$3
18 | isEqual(QT_MAJOR_VERSION, $$maj) {
19 | isEqual(QT_MINOR_VERSION, $$min) {
20 | isEqual(QT_PATCH_VERSION, $$patch) {
21 | return(true)
22 | }
23 | greaterThan(QT_PATCH_VERSION, $$patch) {
24 | return(true)
25 | }
26 | }
27 | greaterThan(QT_MINOR_VERSION, $$min) {
28 | return(true)
29 | }
30 | }
31 | greaterThan(QT_MAJOR_VERSION, $$maj) {
32 | return(true)
33 | }
34 | return(false)
35 | }
36 |
37 | !minQtVersion(5, 2, 0) {
38 | message("Cannot build jom with Qt version $${QT_VERSION}.")
39 | error("Use at least Qt 5.2.0.")
40 | }
41 |
--------------------------------------------------------------------------------
/src/app/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | file(READ version.txt version)
2 | string(REGEX REPLACE "[\r\n]" "" version ${version})
3 | string(REPLACE "." ";" version_list ${version})
4 | list(GET version_list 0 JOM_VERSION_MAJOR)
5 | list(GET version_list 1 JOM_VERSION_MINOR)
6 | list(GET version_list 2 JOM_VERSION_PATCH)
7 |
8 | configure_file(
9 | app.rc.in
10 | app.rc)
11 |
12 | add_executable(jom
13 | application.cpp
14 | application.h
15 | main.cpp
16 | ${CMAKE_CURRENT_BINARY_DIR}/app.rc
17 | )
18 |
19 | target_compile_definitions(jom
20 | PRIVATE JOM_VERSION_MAJOR=${JOM_VERSION_MAJOR}
21 | PRIVATE JOM_VERSION_MINOR=${JOM_VERSION_MINOR}
22 | PRIVATE JOM_VERSION_PATCH=${JOM_VERSION_PATCH}
23 | )
24 |
25 | set_target_properties(jom PROPERTIES DEBUG_POSTFIX d)
26 | target_link_libraries(jom PRIVATE jomlib)
27 |
28 | install(TARGETS jom RUNTIME DESTINATION bin
29 | LIBRARY DESTINATION lib
30 | ARCHIVE DESTINATION lib)
31 |
--------------------------------------------------------------------------------
/src/app/app.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = app
2 | DESTDIR = ../../bin
3 | QT = core
4 | CONFIG += console
5 | DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII
6 | TARGET = jom
7 | CONFIG(debug, debug|release) {
8 | TARGET = $$join(TARGET,,,d)
9 | }
10 |
11 | PROJECT_BUILD_ROOT=$$OUT_PWD/../..
12 | include(../jomlib/use_jomlib.pri)
13 |
14 | contains(QMAKE_CXXFLAGS_RELEASE, -MT) {
15 | QMAKE_LFLAGS_RELEASE += /NODEFAULTLIB:msvcrt
16 | }
17 |
18 | INCLUDEPATH += ../jomlib
19 | HEADERS = application.h
20 | SOURCES = main.cpp application.cpp
21 | RESOURCES = app.qrc
22 |
23 | JOM_VERSION = $$cat(version.txt, lines)
24 | JOM_VERSION = $$first(JOM_VERSION)
25 | JOM_VERSION_MAJOR=$$section(JOM_VERSION, '.', 0, 0)
26 | JOM_VERSION_MINOR=$$section(JOM_VERSION, '.', 1, 1)
27 | JOM_VERSION_PATCH=$$section(JOM_VERSION, '.', 2, 2)
28 | DEFINES += JOM_VERSION_MAJOR=$$JOM_VERSION_MAJOR
29 | DEFINES += JOM_VERSION_MINOR=$$JOM_VERSION_MINOR
30 | DEFINES += JOM_VERSION_PATCH=$$JOM_VERSION_PATCH
31 |
32 | content = $$cat(app.rc.in, blob)
33 | content ~= s/@\([^@]+\)@/\$\${\1}/g
34 | content ~= s/\"/\\\"/g
35 | write_file($$OUT_PWD/jom.rc.in, content)
36 | rcsubst.input = $$OUT_PWD/jom.rc.in
37 | rcsubst.output = $$OUT_PWD/jom.rc
38 | QMAKE_SUBSTITUTES += rcsubst
39 | RC_FILE += $$OUT_PWD/jom.rc
40 |
--------------------------------------------------------------------------------
/src/app/app.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | qt.conf
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/app/app.rc.in:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | VS_VERSION_INFO VERSIONINFO
4 | FILEVERSION @JOM_VERSION_MAJOR@,@JOM_VERSION_MINOR@,@JOM_VERSION_PATCH@,0
5 | PRODUCTVERSION @JOM_VERSION_MAJOR@,@JOM_VERSION_MINOR@,@JOM_VERSION_PATCH@,0
6 | FILEFLAGSMASK 0x3fL
7 | #ifdef _DEBUG
8 | FILEFLAGS VS_FF_DEBUG
9 | #else
10 | FILEFLAGS 0x0L
11 | #endif
12 | FILEOS VOS__WINDOWS32
13 | FILETYPE VFT_APP
14 | FILESUBTYPE 0x0L
15 | BEGIN
16 | BLOCK "StringFileInfo"
17 | BEGIN
18 | BLOCK "040904b0"
19 | BEGIN
20 | VALUE "CompanyName", "The Qt Company Ltd.\0"
21 | VALUE "FileDescription", "jom - a parallel make tool\0"
22 | VALUE "FileVersion", "@JOM_VERSION@.0\0"
23 | VALUE "LegalCopyright", "Copyright (C) 2019 The Qt Company Ltd.\0"
24 | VALUE "OriginalFilename", "jom.exe\0"
25 | VALUE "ProductName", "jom\0"
26 | VALUE "ProductVersion", "@JOM_VERSION@.0\0"
27 | END
28 | END
29 | BLOCK "VarFileInfo"
30 | BEGIN
31 | VALUE "Translation", 0x0409, 1200
32 | END
33 | END
34 | /* End of Version info */
35 |
--------------------------------------------------------------------------------
/src/app/application.cpp:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #include "application.h"
27 | #include
28 |
29 | #include
30 | #include
31 | #include
32 | #include
33 |
34 | namespace NMakeFile {
35 |
36 | static bool isSubJOM()
37 | {
38 | return GetEnvironmentVariableA("_JOMSRVKEY_", NULL, 0) > 0;
39 | }
40 |
41 | Application::Application(int &argc, char **argv)
42 | : QCoreApplication(argc, argv)
43 | {
44 | m_bIsSubJOM = NMakeFile::isSubJOM();
45 | }
46 |
47 | Application::~Application()
48 | {
49 | IoCompletionPort::destroyInstance();
50 | }
51 |
52 | void Application::exit(int exitCode)
53 | {
54 | QCoreApplication::exit(exitCode);
55 | }
56 |
57 | } // namespace NMakeFile
58 |
--------------------------------------------------------------------------------
/src/app/application.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef APPLICATION_H
27 | #define APPLICATION_H
28 |
29 | #include
30 |
31 | namespace NMakeFile {
32 |
33 | class Application : public QCoreApplication
34 | {
35 | Q_OBJECT
36 | public:
37 | static Application *instance() { return static_cast(QCoreApplication::instance()); }
38 |
39 | Application(int &argc, char **argv);
40 | ~Application();
41 |
42 | bool isSubJOM() const { return m_bIsSubJOM; }
43 |
44 | public slots:
45 | void exit(int exitCode);
46 |
47 | private:
48 | bool m_bIsSubJOM;
49 | };
50 |
51 | } // namespace NMakeFile
52 |
53 | #endif // APPLICATION_H
54 |
--------------------------------------------------------------------------------
/src/app/main.cpp:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #include "application.h"
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 |
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 |
42 | #include
43 | #include
44 |
45 | using namespace NMakeFile;
46 |
47 | static void showLogo()
48 | {
49 | fprintf(stderr, "\njom %d.%d.%d - empower your cores\n\n",
50 | JOM_VERSION_MAJOR, JOM_VERSION_MINOR, JOM_VERSION_PATCH);
51 | fflush(stderr);
52 | }
53 |
54 | static void showUsage()
55 | {
56 | printf("Usage: jom @commandfile\n"
57 | " jom [options] [/f makefile] [macro definitions] [targets]\n\n"
58 | "nmake compatible options:\n"
59 | "/A build all targets\n"
60 | "/D display build information\n"
61 | "/E override environment variable macros\n"
62 | "/F use the specified makefile\n"
63 | "/G display included makefiles\n"
64 | "/H show help\n"
65 | "/I ignore all exit codes\n"
66 | "/K keep going - build unrelated targets on error\n"
67 | "/N dry run - just print commands\n"
68 | "/NOLOGO do not print logo\n"
69 | "/P print makefile info\n"
70 | "/R ignore predefined rules and macros\n"
71 | "/S silent mode\n"
72 | "/U print content of inline files\n"
73 | "/L same as /NOLOGO\n"
74 | "/W print the working directory before and after other processing\n"
75 | "/X write stderr to file.\n"
76 | "/Y disable batch mode inference rules\n\n"
77 | "jom only options:\n"
78 | "/DUMPGRAPH show the generated dependency graph\n"
79 | "/DUMPGRAPHDOT dump dependency graph in dot format\n"
80 | "/J use up to n processes in parallel\n"
81 | "/VERSION print version and exit\n");
82 | }
83 |
84 | static TargetExecutor* g_pTargetExecutor = 0;
85 |
86 | BOOL WINAPI ConsoleCtrlHandlerRoutine(DWORD dwCtrlType)
87 | {
88 | Q_UNUSED(dwCtrlType);
89 | fprintf(stderr, "jom terminated by user (pid=%lld)\n", QCoreApplication::applicationPid());
90 | fflush(stderr);
91 |
92 | GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
93 | if (g_pTargetExecutor)
94 | g_pTargetExecutor->removeTempFiles();
95 |
96 | exit(2);
97 | return TRUE;
98 | }
99 |
100 | QStringList getCommandLineArguments()
101 | {
102 | QStringList commandLineArguments = qApp->arguments().mid(1);
103 | QString makeFlags = qGetEnvironmentVariable(L"JOMFLAGS");
104 | if (makeFlags.isEmpty())
105 | makeFlags = qGetEnvironmentVariable(L"MAKEFLAGS");
106 | if (!makeFlags.isEmpty())
107 | commandLineArguments.prepend(QLatin1Char('/') + makeFlags);
108 | return commandLineArguments;
109 | }
110 |
111 | static bool initJobServer(const Application &app, ProcessEnvironment *environment,
112 | JobServer **outJobServer)
113 | {
114 | bool mustCreateJobServer = false;
115 | if (app.isSubJOM()) {
116 | int inheritedMaxNumberOfJobs = g_options.maxNumberOfJobs;
117 | const QString str = environment->value(QLatin1String("_JOMJOBCOUNT_"));
118 | if (!str.isEmpty()) {
119 | bool ok;
120 | const int n = str.toInt(&ok);
121 | if (ok && n > 0)
122 | inheritedMaxNumberOfJobs = n;
123 | }
124 | if (g_options.isMaxNumberOfJobsSet
125 | && g_options.maxNumberOfJobs != inheritedMaxNumberOfJobs)
126 | {
127 | fprintf(stderr, "jom: Overriding inherited number of jobs %d with %d. "
128 | "New jobserver created.\n",
129 | inheritedMaxNumberOfJobs, g_options.maxNumberOfJobs);
130 | mustCreateJobServer = true;
131 | }
132 | } else {
133 | mustCreateJobServer = true;
134 | }
135 |
136 | if (mustCreateJobServer) {
137 | JobServer *jobServer = new JobServer(environment);
138 | *outJobServer = jobServer;
139 | if (!jobServer->start(g_options.maxNumberOfJobs)) {
140 | fprintf(stderr, "Cannot start job server: %s.", qPrintable(jobServer->errorString()));
141 | return false;
142 | }
143 | }
144 | return true;
145 | }
146 |
147 | int main(int argc, char* argv[])
148 | {
149 | int result = 0;
150 | try {
151 | SetConsoleCtrlHandler(&ConsoleCtrlHandlerRoutine, TRUE);
152 | Application app(argc, argv);
153 | QTextCodec::setCodecForLocale(QTextCodec::codecForName("IBM 850"));
154 | MakefileFactory mf;
155 | Options* options = 0;
156 | mf.setEnvironment(QProcess::systemEnvironment());
157 | if (!mf.apply(getCommandLineArguments(), &options)) {
158 | switch (mf.errorType()) {
159 | case MakefileFactory::CommandLineError:
160 | showUsage();
161 | return 128;
162 | case MakefileFactory::ParserError:
163 | case MakefileFactory::IOError:
164 | fprintf(stderr, "Error: %s\n", qPrintable(mf.errorString()));
165 | return 2;
166 | }
167 | }
168 |
169 | if (options->showUsageAndExit) {
170 | if (options->showLogo)
171 | showLogo();
172 | showUsage();
173 | return 0;
174 | } else if (options->showVersionAndExit) {
175 | printf("jom version %d.%d.%d\n", JOM_VERSION_MAJOR, JOM_VERSION_MINOR, JOM_VERSION_PATCH);
176 | return 0;
177 | }
178 |
179 | if (options->showLogo && !app.isSubJOM())
180 | showLogo();
181 |
182 | QScopedPointer mkfile(mf.makefile());
183 | if (options->displayMakeInformation) {
184 | printf("MACROS:\n\n");
185 | mkfile->macroTable()->dump();
186 | printf("\nINFERENCE RULES:\n\n");
187 | mkfile->dumpInferenceRules();
188 | printf("\nTARGETS:\n\n");
189 | mkfile->dumpTargets();
190 | }
191 |
192 | JobServer *jobServer = 0;
193 | ProcessEnvironment processEnvironment = mkfile->macroTable()->environment();
194 | if (!initJobServer(app, &processEnvironment, &jobServer))
195 | return 3;
196 | QScopedPointer jobServerDeleter(jobServer);
197 |
198 | if (options->printWorkingDir) {
199 | printf("jom: Entering directory '%s\n",
200 | qPrintable(QDir::toNativeSeparators(QDir::currentPath())));
201 | fflush(stdout);
202 | }
203 |
204 | if (mkfile->isParallelExecutionDisabled()) {
205 | printf("jom: parallel job execution disabled for %s\n", qPrintable(mkfile->fileName()));
206 | g_options.maxNumberOfJobs = 1;
207 | }
208 |
209 | TargetExecutor executor(processEnvironment);
210 | QObject::connect(&executor, SIGNAL(finished(int)), &app, SLOT(exit(int)));
211 | g_pTargetExecutor = &executor;
212 | executor.apply(mkfile.data(), mf.activeTargets());
213 |
214 | QMetaObject::invokeMethod(&executor, "startProcesses", Qt::QueuedConnection);
215 | result = app.exec();
216 | g_pTargetExecutor = 0;
217 | if (options->printWorkingDir) {
218 | printf("jom: Leaving directory '%s'\n",
219 | qPrintable(QDir::toNativeSeparators(QDir::currentPath())));
220 | fflush(stdout);
221 | }
222 | } catch (const Exception &e) {
223 | fprintf(stderr, "jom: %s\n", qPrintable(e.message()));
224 | result = 2;
225 | }
226 | return result;
227 | }
228 |
--------------------------------------------------------------------------------
/src/app/qt.conf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qt-labs/jom/5b295dbee66504d21b8cc7d05d5e88e87644d586/src/app/qt.conf
--------------------------------------------------------------------------------
/src/app/version.txt:
--------------------------------------------------------------------------------
1 | 1.1.4
2 |
--------------------------------------------------------------------------------
/src/jomlib/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_library(jomlib STATIC
2 | commandexecutor.cpp
3 | commandexecutor.h
4 | dependencygraph.cpp
5 | dependencygraph.h
6 | exception.cpp
7 | exception.h
8 | fastfileinfo.cpp
9 | fastfileinfo.h
10 | filetime.cpp
11 | filetime.h
12 | helperfunctions.cpp
13 | helperfunctions.h
14 | iocompletionport.cpp
15 | iocompletionport.h
16 | jobclient.cpp
17 | jobclient.h
18 | jobclientacquirehelper.cpp
19 | jobclientacquirehelper.h
20 | jobserver.cpp
21 | jomprocess.cpp
22 | jomprocess.h
23 | macrotable.cpp
24 | macrotable.h
25 | makefile.cpp
26 | makefile.h
27 | makefilefactory.cpp
28 | makefilefactory.h
29 | makefilelinereader.cpp
30 | makefilelinereader.h
31 | options.cpp
32 | options.h
33 | parser.cpp
34 | parser.h
35 | ppexpr_grammar.cpp
36 | ppexpr_grammar_p.h
37 | ppexprparser.cpp
38 | ppexprparser.h
39 | preprocessor.cpp
40 | preprocessor.h
41 | stable.h
42 | targetexecutor.cpp
43 | targetexecutor.h
44 | )
45 |
46 | target_include_directories(jomlib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
47 | target_link_libraries(jomlib PUBLIC Qt5::Core)
48 |
49 | # If we're building against a static Qt on Windows,
50 | # we must link manually against all private libraries.
51 | # This should not be necessary. See QTBUG-38913.
52 | get_target_property(qt_core_type Qt5::Core TYPE)
53 | if(qt_core_type MATCHES STATIC_LIBRARY)
54 | target_link_libraries(jomlib PRIVATE mincore userenv winmm ws2_32)
55 |
56 | if(CMAKE_BUILD_TYPE MATCHES Debug)
57 | set(debug_suffix d)
58 | set(qt_build_config DEBUG)
59 | else()
60 | set(debug_suffix "")
61 | set(qt_build_config RELEASE)
62 | endif()
63 |
64 | get_target_property(qt_core_lib_location Qt5::Core IMPORTED_LOCATION_${qt_build_config})
65 | get_filename_component(qt_core_lib_dir ${qt_core_lib_location} DIRECTORY)
66 | target_link_libraries(jomlib PRIVATE "${qt_core_lib_dir}/qtpcre2${debug_suffix}.lib")
67 | endif()
68 |
69 | target_compile_definitions(jomlib PRIVATE
70 | QT_NO_CAST_FROM_ASCII
71 | QT_NO_CAST_TO_ASCII
72 | UNICODE
73 | )
74 |
75 | if(MSVC)
76 | target_compile_definitions(jomlib PUBLIC
77 | _CRT_SECURE_NO_WARNINGS
78 | )
79 | endif()
80 |
--------------------------------------------------------------------------------
/src/jomlib/commandexecutor.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef COMMANDEXECUTOR_H
27 | #define COMMANDEXECUTOR_H
28 |
29 | #include "makefile.h"
30 | #include "jomprocess.h"
31 | #include
32 | #include
33 |
34 | QT_BEGIN_NAMESPACE
35 | class QStringList;
36 | QT_END_NAMESPACE
37 |
38 | namespace NMakeFile {
39 |
40 | class CommandExecutor : public QObject
41 | {
42 | Q_OBJECT
43 | public:
44 | CommandExecutor(QObject* parent, const ProcessEnvironment &environment);
45 | ~CommandExecutor();
46 |
47 | void start(DescriptionBlock* target);
48 | DescriptionBlock* target() { return m_pTarget; }
49 | bool isActive() const { return m_active; }
50 | void waitForFinished();
51 | void cleanupTempFiles();
52 | void setBufferedOutput(bool b) { m_process.setBufferedOutput(b); }
53 | bool isBufferedOutputSet() const { return m_process.isBufferedOutputSet(); }
54 |
55 | public slots:
56 | void setEnvironment(const ProcessEnvironment &environment);
57 |
58 | signals:
59 | void environmentChanged(const ProcessEnvironment &environment);
60 | void finished(CommandExecutor* process, bool abortMakeProcess);
61 |
62 | private slots:
63 | void onProcessError(Process::ProcessError error);
64 | void onProcessFinished(int exitCode, Process::ExitStatus exitStatus);
65 |
66 | private:
67 | void finishExecution(bool commandFailed);
68 | void executeCurrentCommandLine();
69 | void createTempFiles();
70 | void writeToChannel(const QByteArray& data, FILE *channel);
71 | void writeToStandardOutput(const QByteArray& data);
72 | void writeToStandardError(const QByteArray& data);
73 | bool isSimpleCommandLine(const QString &cmdLine);
74 | bool exec_cd(const QString &commandLine);
75 |
76 | private:
77 | static ulong m_startUpTickCount;
78 | static QString m_tempPath;
79 | Process m_process;
80 | DescriptionBlock* m_pTarget;
81 |
82 | struct TempFile
83 | {
84 | QFile* file;
85 | bool keep;
86 | };
87 |
88 | QList m_tempFiles;
89 | int m_currentCommandIdx;
90 | QString m_nextWorkingDir;
91 | bool m_ignoreProcessErrors;
92 | bool m_active;
93 | };
94 |
95 | } // namespace NMakeFile
96 |
97 | #endif // COMMANDEXECUTOR_H
98 |
--------------------------------------------------------------------------------
/src/jomlib/dependencygraph.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef DEPENDENCYGRAPH_H
27 | #define DEPENDENCYGRAPH_H
28 |
29 | #include
30 | #include
31 |
32 | namespace NMakeFile {
33 |
34 | class DescriptionBlock;
35 |
36 | class DependencyGraph
37 | {
38 | public:
39 | DependencyGraph();
40 | ~DependencyGraph();
41 |
42 | void build(DescriptionBlock* target);
43 | void markParentsRecursivlyUnbuildable(DescriptionBlock *target);
44 | bool isUnbuildable(DescriptionBlock *target) const;
45 | bool isEmpty() const;
46 | void removeLeaf(DescriptionBlock* target);
47 | DescriptionBlock *findAvailableTarget(bool ignoreTimeStamps);
48 | void dump();
49 | void dotDump();
50 | void clear();
51 |
52 | private:
53 | bool isTargetUpToDate(DescriptionBlock* target);
54 |
55 | struct Node
56 | {
57 | enum State {UnknownState, ExecutingState, Unbuildable};
58 |
59 | State state;
60 | DescriptionBlock* target;
61 | QList children;
62 | QList parents;
63 | };
64 |
65 | Node* createNode(DescriptionBlock* target, Node* parent);
66 | void deleteNode(Node* node);
67 | void removeLeaf(Node* node);
68 | void internalBuild(Node *node, QSet &seen);
69 | void addEdge(Node* parent, Node* child);
70 | void internalDump(Node* node, QString& indent);
71 | void internalDotDump(Node* node, const QString& parent);
72 | void displayNodeBuildInfo(Node* node, bool isUpToDate);
73 | static void markParentsRecursivlyUnbuildable(Node *node);
74 |
75 | private:
76 | Node* m_root;
77 | QHash m_nodeContainer;
78 | QList m_leaves;
79 | bool m_bDirtyLeaves;
80 | };
81 |
82 | } // namespace NMakeFile
83 |
84 | #endif // DEPENDENCYGRAPH_H
85 |
--------------------------------------------------------------------------------
/src/jomlib/exception.cpp:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #include "exception.h"
27 |
28 | #include
29 |
30 | namespace NMakeFile {
31 |
32 | Exception::Exception(const QString& message)
33 | : m_message(message)
34 | {
35 | }
36 |
37 | const QString Exception::toString() const
38 | {
39 | return m_message;
40 | }
41 |
42 | FileException::FileException(const QString& message, const QString& fileName, int line)
43 | : Exception(message),
44 | m_fileName(fileName),
45 | m_line(line)
46 | {
47 | }
48 |
49 | const QString FileException::toString() const
50 | {
51 | QString output = m_message;
52 | if (!m_fileName.isEmpty()) {
53 | output += QLatin1String(" in ");
54 | QString fileName = m_fileName;
55 | fileName = QDir::toNativeSeparators(fileName);
56 | output += fileName;
57 | output += QLatin1String(" ");
58 | }
59 |
60 | if (m_line > 0) {
61 | output += QString::fromLatin1("line %1").arg(m_line);
62 | }
63 |
64 | return output;
65 | }
66 |
67 | } // namespace NMakeFile
68 |
--------------------------------------------------------------------------------
/src/jomlib/exception.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef EXCEPTION_H
27 | #define EXCEPTION_H
28 |
29 | #include
30 |
31 | namespace NMakeFile {
32 |
33 | class Exception
34 | {
35 | public:
36 | explicit Exception(const QString& message = QString());
37 |
38 | const QString& message() const { return m_message; }
39 | virtual const QString toString() const;
40 |
41 | protected:
42 | QString m_message;
43 | };
44 |
45 | class FileException : public Exception
46 | {
47 | public:
48 | explicit FileException(const QString& message = QString(), const QString& fileName = QString(), int line = 0);
49 |
50 | const QString& fileName() const { return m_fileName; }
51 | int line() const { return m_line; }
52 | const QString toString() const;
53 |
54 | protected:
55 | QString m_fileName;
56 | int m_line;
57 | };
58 |
59 | } // namespace NMakeFile
60 |
61 | #endif // EXCEPTION_H
62 |
--------------------------------------------------------------------------------
/src/jomlib/fastfileinfo.cpp:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #include "fastfileinfo.h"
27 |
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | namespace NMakeFile {
34 |
35 | static_assert(sizeof(FastFileInfo::InternalType) == sizeof(WIN32_FILE_ATTRIBUTE_DATA),
36 | "FastFileInfo::InternalType has wrong size");
37 |
38 | inline WIN32_FILE_ATTRIBUTE_DATA* z(FastFileInfo::InternalType &internalData)
39 | {
40 | return reinterpret_cast(&internalData);
41 | }
42 |
43 | inline const WIN32_FILE_ATTRIBUTE_DATA* z(const FastFileInfo::InternalType &internalData)
44 | {
45 | return reinterpret_cast(&internalData);
46 | }
47 |
48 | static WIN32_FILE_ATTRIBUTE_DATA createInvalidFAD()
49 | {
50 | WIN32_FILE_ATTRIBUTE_DATA fad = {0};
51 | fad.dwFileAttributes = INVALID_FILE_ATTRIBUTES;
52 | return fad;
53 | }
54 |
55 | static QHash fadHash;
56 |
57 | FastFileInfo::FastFileInfo(const QString &fileName)
58 | {
59 | static const WIN32_FILE_ATTRIBUTE_DATA invalidFAD = createInvalidFAD();
60 | *z(m_attributes) = fadHash.value(fileName, invalidFAD);
61 | if (z(m_attributes)->dwFileAttributes != INVALID_FILE_ATTRIBUTES)
62 | return;
63 |
64 | static const QString longPathPrefix = QStringLiteral("\\\\?\\");
65 | QString nativeFilePath = QDir::toNativeSeparators(QFileInfo(fileName).absoluteFilePath());
66 | if (!nativeFilePath.startsWith(longPathPrefix))
67 | nativeFilePath.prepend(longPathPrefix);
68 |
69 | if (!GetFileAttributesEx(reinterpret_cast(nativeFilePath.utf16()),
70 | GetFileExInfoStandard, &m_attributes))
71 | {
72 | z(m_attributes)->dwFileAttributes = INVALID_FILE_ATTRIBUTES;
73 | return;
74 | }
75 |
76 | fadHash.insert(fileName, *z(m_attributes));
77 | }
78 |
79 | bool FastFileInfo::exists() const
80 | {
81 | return z(m_attributes)->dwFileAttributes != INVALID_FILE_ATTRIBUTES;
82 | }
83 |
84 | FileTime FastFileInfo::lastModified() const
85 | {
86 | const WIN32_FILE_ATTRIBUTE_DATA *fattr = z(m_attributes);
87 | if (fattr->dwFileAttributes == INVALID_FILE_ATTRIBUTES) {
88 | return FileTime();
89 | } else {
90 | return FileTime(reinterpret_cast(fattr->ftLastWriteTime));
91 | }
92 | }
93 |
94 | void FastFileInfo::clearCacheForFile(const QString &fileName)
95 | {
96 | fadHash.remove(fileName);
97 | }
98 |
99 | } // NMakeFile
100 |
--------------------------------------------------------------------------------
/src/jomlib/fastfileinfo.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef FASTFILEINFO_H
27 | #define FASTFILEINFO_H
28 |
29 | #include "filetime.h"
30 |
31 | namespace NMakeFile {
32 |
33 | class FastFileInfo
34 | {
35 | public:
36 | FastFileInfo(const QString &fileName);
37 |
38 | bool exists() const;
39 | FileTime lastModified() const;
40 |
41 | static void clearCacheForFile(const QString &fileName);
42 |
43 | struct InternalType
44 | {
45 | quint8 z[36];
46 | };
47 |
48 | private:
49 | InternalType m_attributes;
50 | };
51 |
52 | } // NMakeFile
53 |
54 | #endif // FASTFILEINFO_H
55 |
--------------------------------------------------------------------------------
/src/jomlib/filetime.cpp:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #include "filetime.h"
27 | #include
28 | #include
29 |
30 | namespace NMakeFile {
31 |
32 | static_assert(sizeof(FileTime::InternalType) == sizeof(FILETIME),
33 | "FileTime::InternalType has wrong size");
34 |
35 | FileTime::FileTime()
36 | : m_fileTime(0)
37 | {
38 | }
39 |
40 | bool FileTime::operator < (const FileTime &rhs) const
41 | {
42 | const FILETIME *const t1 = reinterpret_cast(&m_fileTime);
43 | const FILETIME *const t2 = reinterpret_cast(&rhs.m_fileTime);
44 | return CompareFileTime(t1, t2) < 0;
45 | }
46 |
47 | void FileTime::clear()
48 | {
49 | m_fileTime = 0;
50 | }
51 |
52 | bool FileTime::isValid() const
53 | {
54 | return m_fileTime != 0;
55 | }
56 |
57 | FileTime FileTime::currentTime()
58 | {
59 | FileTime result;
60 | SYSTEMTIME st;
61 | GetSystemTime(&st);
62 | FILETIME *const ft = reinterpret_cast(&result.m_fileTime);
63 | SystemTimeToFileTime(&st, ft);
64 | return result;
65 | }
66 |
67 | QString FileTime::toString() const
68 | {
69 | const FILETIME *const ft = reinterpret_cast(&m_fileTime);
70 | SYSTEMTIME stUTC, stLocal;
71 | FileTimeToSystemTime(ft, &stUTC);
72 | SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
73 | WCHAR szString[512];
74 | HRESULT hr = StringCchPrintf(szString, sizeof(szString) / sizeof(WCHAR),
75 | L"%02d.%02d.%d %02d:%02d:%02d",
76 | stLocal.wDay, stLocal.wMonth, stLocal.wYear,
77 | stLocal.wHour, stLocal.wMinute, stLocal.wSecond);
78 | return SUCCEEDED(hr) ? QString::fromUtf16((unsigned short*)szString) : QString();
79 | }
80 |
81 | } // namespace NMakeFile
82 |
--------------------------------------------------------------------------------
/src/jomlib/filetime.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef FILETIME_H
27 | #define FILETIME_H
28 |
29 | #include
30 | #include
31 |
32 | namespace NMakeFile {
33 |
34 | class FileTime
35 | {
36 | public:
37 | FileTime();
38 |
39 | typedef quint64 InternalType;
40 |
41 | FileTime(const InternalType &ft)
42 | : m_fileTime(ft)
43 | { }
44 |
45 | bool operator < (const FileTime &rhs) const;
46 | bool operator <= (const FileTime &rhs) const
47 | {
48 | return operator < (rhs) || operator == (rhs);
49 | }
50 | bool operator == (const FileTime &rhs) const
51 | {
52 | return m_fileTime == rhs.m_fileTime;
53 | }
54 |
55 | void clear();
56 | bool isValid() const;
57 | QString toString() const;
58 | InternalType internalRepresentation() const { return m_fileTime; }
59 |
60 | static FileTime currentTime();
61 |
62 | private:
63 | friend class FastFileInfo;
64 | InternalType m_fileTime;
65 | };
66 |
67 | } // namespace NMakeFile
68 |
69 | #endif // FILETIME_H
70 |
--------------------------------------------------------------------------------
/src/jomlib/helperfunctions.cpp:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #include "helperfunctions.h"
27 | #include
28 |
29 | /**
30 | * Splits the string, respects "foo bar" and "foo ""knuffi"" bar".
31 | */
32 | QStringList splitCommandLine(QString commandLine)
33 | {
34 | QString str;
35 | QStringList arguments;
36 | commandLine.append(QLatin1Char(' ')); // append artificial space
37 | bool escapedQuote = false;
38 | bool insideQuotes = false;
39 | for (int i=0; i < commandLine.count(); ++i) {
40 | if (commandLine.at(i).isSpace() && !insideQuotes) {
41 | escapedQuote = false;
42 | str = str.trimmed();
43 | if (!str.isEmpty()) {
44 | arguments.append(str);
45 | str.clear();
46 | }
47 | } else {
48 | if (commandLine.at(i) == QLatin1Char('"')) {
49 | if (escapedQuote) {
50 | str.append(QLatin1Char('"'));
51 | escapedQuote = false;
52 | } else {
53 | escapedQuote = true;
54 | }
55 | insideQuotes = !insideQuotes;
56 | } else {
57 | str.append(commandLine.at(i));
58 | escapedQuote = false;
59 | }
60 | }
61 | }
62 | return arguments;
63 | }
64 |
65 | QString trimLeft(const QString &s)
66 | {
67 | QString result = s;
68 | while (!result.isEmpty() && result[0].isSpace())
69 | result.remove(0, 1);
70 | return result;
71 | }
72 |
73 | QString qGetEnvironmentVariable(const wchar_t *lpName)
74 | {
75 | const size_t bufferSize = 32767;
76 | TCHAR buffer[bufferSize];
77 | if (GetEnvironmentVariable(lpName, buffer, bufferSize))
78 | return QString::fromWCharArray(buffer);
79 | return QString();
80 | }
81 |
82 | bool qSetEnvironmentVariable(const QString &name, const QString &value)
83 | {
84 | return SetEnvironmentVariable(
85 | reinterpret_cast(name.utf16()),
86 | reinterpret_cast(value.utf16()));
87 | }
88 |
--------------------------------------------------------------------------------
/src/jomlib/helperfunctions.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef HELPERFUNCTIONS_H
27 | #define HELPERFUNCTIONS_H
28 |
29 | #include
30 | #include
31 |
32 | inline QString fileNameFromFilePath(const QString& filePath)
33 | {
34 | int idx = qMax(filePath.lastIndexOf(QLatin1Char('/')), filePath.lastIndexOf(QLatin1Char('\\')));
35 | if (idx == -1)
36 | return filePath;
37 | QString fileName = filePath;
38 | fileName.remove(0, idx+1);
39 | return fileName;
40 | }
41 |
42 | inline bool isSpaceOrTab(const QChar& ch)
43 | {
44 | return ch == QLatin1Char(' ') || ch == QLatin1Char('\t');
45 | }
46 |
47 | inline bool startsWithSpaceOrTab(const QString& str)
48 | {
49 | Q_ASSERT(!str.isEmpty());
50 | return isSpaceOrTab(str.at(0));
51 | }
52 |
53 | inline void removeDirSeparatorAtEnd(QString& directory)
54 | {
55 | if (directory.endsWith(QLatin1Char('/')) || directory.endsWith(QLatin1Char('\\')))
56 | directory.chop(1);
57 | }
58 |
59 | inline void removeDoubleQuotes(QString& targetName)
60 | {
61 | const QChar dblQuote = QLatin1Char('"');
62 | if (targetName.startsWith(dblQuote) && targetName.endsWith(dblQuote)) {
63 | targetName.chop(1);
64 | targetName.remove(0, 1);
65 | }
66 | }
67 |
68 | /**
69 | * Splits the string, respects "foo bar" and "foo ""knuffi"" bar".
70 | */
71 | QStringList splitCommandLine(QString commandLine);
72 |
73 | /**
74 | * Returns a copy of s with all whitespace removed from the left.
75 | */
76 | QString trimLeft(const QString &s);
77 |
78 | QString qGetEnvironmentVariable(const wchar_t *lpName);
79 | bool qSetEnvironmentVariable(const QString &name, const QString &value);
80 |
81 | #endif // HELPERFUNCTIONS_H
82 |
--------------------------------------------------------------------------------
/src/jomlib/iocompletionport.cpp:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #include "iocompletionport.h"
27 |
28 | namespace NMakeFile {
29 |
30 | IoCompletionPort *IoCompletionPort::m_instance = 0;
31 |
32 | IoCompletionPort::IoCompletionPort()
33 | : hPort(INVALID_HANDLE_VALUE)
34 | {
35 | setObjectName(QLatin1String("I/O completion port thread"));
36 | HANDLE hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0);
37 | if (!hIOCP) {
38 | qWarning("CreateIoCompletionPort failed with error code %d.\n", GetLastError());
39 | return;
40 | }
41 | hPort = hIOCP;
42 | }
43 |
44 | IoCompletionPort::~IoCompletionPort()
45 | {
46 | PostQueuedCompletionStatus(hPort, 0, NULL, NULL);
47 | QThread::wait();
48 | CloseHandle(hPort);
49 | }
50 |
51 | IoCompletionPort *IoCompletionPort::instance()
52 | {
53 | if (!m_instance)
54 | m_instance = new IoCompletionPort;
55 | return m_instance;
56 | }
57 |
58 | void IoCompletionPort::destroyInstance()
59 | {
60 | delete m_instance;
61 | m_instance = 0;
62 | }
63 |
64 | void IoCompletionPort::registerObserver(IoCompletionPortObserver *observer, HANDLE hFile)
65 | {
66 | HANDLE hIOCP = CreateIoCompletionPort(hFile, hPort, reinterpret_cast(observer), 0);
67 | if (!hIOCP) {
68 | qWarning("Can't associate file handle with I/O completion port. Error code %d.\n", GetLastError());
69 | return;
70 | }
71 | mutex.lock();
72 | observers.insert(observer);
73 | mutex.unlock();
74 | if (!QThread::isRunning())
75 | QThread::start();
76 | }
77 |
78 | void IoCompletionPort::unregisterObserver(IoCompletionPortObserver *observer)
79 | {
80 | mutex.lock();
81 | observers.remove(observer);
82 | mutex.unlock();
83 | }
84 |
85 | void IoCompletionPort::run()
86 | {
87 | DWORD dwBytesRead;
88 | ULONG_PTR pulCompletionKey;
89 | OVERLAPPED *overlapped;
90 |
91 | for (;;) {
92 | BOOL success = GetQueuedCompletionStatus(hPort,
93 | &dwBytesRead,
94 | &pulCompletionKey,
95 | &overlapped,
96 | INFINITE);
97 |
98 | DWORD errorCode = success ? ERROR_SUCCESS : GetLastError();
99 | if (!success && !overlapped) {
100 | printf("GetQueuedCompletionStatus failed with error code %d.\n", errorCode);
101 | return;
102 | }
103 |
104 | if (success && !(dwBytesRead || pulCompletionKey || overlapped)) {
105 | // We've posted null values via PostQueuedCompletionStatus to end this thread.
106 | return;
107 | }
108 |
109 | IoCompletionPortObserver *observer = reinterpret_cast(pulCompletionKey);
110 | mutex.lock();
111 | if (observers.contains(observer))
112 | observer->completionPortNotified(dwBytesRead, errorCode);
113 | mutex.unlock();
114 | }
115 | }
116 |
117 | } // namespace NMakeFile
118 |
--------------------------------------------------------------------------------
/src/jomlib/iocompletionport.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef IOCOMPLETIONPORT_H
27 | #define IOCOMPLETIONPORT_H
28 |
29 | #include
30 | #include
31 | #include
32 | #include
33 |
34 | namespace NMakeFile {
35 |
36 | class IoCompletionPortObserver
37 | {
38 | public:
39 | virtual void completionPortNotified(DWORD numberOfBytes, DWORD errorCode) = 0;
40 | };
41 |
42 | class IoCompletionPort : protected QThread
43 | {
44 | public:
45 | static IoCompletionPort *instance();
46 | static void destroyInstance();
47 |
48 | void registerObserver(IoCompletionPortObserver *notifier, HANDLE hFile);
49 | void unregisterObserver(IoCompletionPortObserver *notifier);
50 |
51 | protected:
52 | void run();
53 |
54 | private:
55 | IoCompletionPort();
56 | ~IoCompletionPort();
57 |
58 | static IoCompletionPort *m_instance;
59 | HANDLE hPort;
60 | QSet observers;
61 | QMutex mutex;
62 | };
63 |
64 | } // namespace NMakeFile
65 |
66 | #endif // IOCOMPLETIONPORT_H
67 |
--------------------------------------------------------------------------------
/src/jomlib/jobclient.cpp:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #include "jobclient.h"
27 | #include "jobclientacquirehelper.h"
28 | #include "helperfunctions.h"
29 |
30 | #include
31 | #include
32 |
33 | namespace NMakeFile {
34 |
35 | JobClient::JobClient(ProcessEnvironment *environment, QObject *parent)
36 | : QObject(parent)
37 | , m_environment(environment)
38 | , m_semaphore(0)
39 | , m_acquireThread(new QThread(this))
40 | , m_acquireHelper(0)
41 | , m_isAcquiring(false)
42 | {
43 | }
44 |
45 | JobClient::~JobClient()
46 | {
47 | if (isAcquiring())
48 | qWarning("JobClient destroyed while still acquiring.");
49 | m_acquireThread->quit();
50 | m_acquireThread->wait(2500);
51 | delete m_acquireHelper;
52 | delete m_semaphore;
53 | }
54 |
55 | bool JobClient::start()
56 | {
57 | Q_ASSERT(!m_semaphore && !m_acquireHelper);
58 | Q_ASSERT(!m_acquireThread->isRunning());
59 |
60 | const QString semaphoreKey = m_environment->value(QLatin1String("_JOMSRVKEY_"));
61 | if (semaphoreKey.isEmpty()) {
62 | setError(QLatin1String("Cannot determine jobserver name."));
63 | return false;
64 | }
65 | m_semaphore = new QSystemSemaphore(semaphoreKey);
66 | if (m_semaphore->error() != QSystemSemaphore::NoError) {
67 | setError(m_semaphore->errorString());
68 | return false;
69 | }
70 |
71 | m_acquireHelper = new JobClientAcquireHelper(m_semaphore);
72 | m_acquireHelper->moveToThread(m_acquireThread);
73 | connect(this, &JobClient::startAcquisition, m_acquireHelper, &JobClientAcquireHelper::acquire);
74 | connect(m_acquireHelper, &JobClientAcquireHelper::acquired, this, &JobClient::onHelperAcquired);
75 | m_acquireThread->start();
76 | return true;
77 | }
78 |
79 | void JobClient::asyncAcquire()
80 | {
81 | Q_ASSERT(m_semaphore);
82 | Q_ASSERT(m_acquireHelper);
83 | Q_ASSERT(m_acquireThread->isRunning());
84 |
85 | m_isAcquiring = true;
86 | emit startAcquisition();
87 | }
88 |
89 | void JobClient::onHelperAcquired()
90 | {
91 | m_isAcquiring = false;
92 | emit acquired();
93 | }
94 |
95 | bool JobClient::isAcquiring() const
96 | {
97 | return m_isAcquiring;
98 | }
99 |
100 | void JobClient::release()
101 | {
102 | Q_ASSERT(m_semaphore);
103 |
104 | if (!m_semaphore->release())
105 | qWarning("QSystemSemaphore::release failed: %s (%d)",
106 | qPrintable(m_semaphore->errorString()), m_semaphore->error());
107 | }
108 |
109 | QString JobClient::errorString() const
110 | {
111 | return m_errorString;
112 | }
113 |
114 | void JobClient::setError(const QString &errorMessage)
115 | {
116 | m_errorString = errorMessage;
117 | }
118 |
119 | } // namespace NMakeFile
120 |
--------------------------------------------------------------------------------
/src/jomlib/jobclient.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef JOBCLIENT_H
27 | #define JOBCLIENT_H
28 |
29 | #include "processenvironment.h"
30 | #include
31 |
32 | QT_BEGIN_NAMESPACE
33 | class QSystemSemaphore;
34 | class QThread;
35 | QT_END_NAMESPACE
36 |
37 | namespace NMakeFile {
38 |
39 | class JobClientAcquireHelper;
40 |
41 | class JobClient : public QObject
42 | {
43 | Q_OBJECT
44 | public:
45 | explicit JobClient(ProcessEnvironment *environment, QObject *parent = 0);
46 | ~JobClient();
47 |
48 | bool start();
49 | void asyncAcquire();
50 | bool isAcquiring() const;
51 | void release();
52 | QString errorString() const;
53 |
54 | signals:
55 | void startAcquisition();
56 | void acquired();
57 |
58 | private slots:
59 | void onHelperAcquired();
60 |
61 | private:
62 | void setError(const QString &errorMessage);
63 |
64 | ProcessEnvironment *m_environment;
65 | QString m_errorString;
66 | QSystemSemaphore *m_semaphore;
67 | QThread *m_acquireThread;
68 | JobClientAcquireHelper *m_acquireHelper;
69 | bool m_isAcquiring;
70 | };
71 |
72 | } // namespace NMakeFile
73 |
74 | #endif // JOBCLIENT_H
75 |
--------------------------------------------------------------------------------
/src/jomlib/jobclientacquirehelper.cpp:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #include "jobclientacquirehelper.h"
27 |
28 | namespace NMakeFile {
29 |
30 | JobClientAcquireHelper::JobClientAcquireHelper(QSystemSemaphore *semaphore)
31 | : m_semaphore(semaphore)
32 | {
33 | }
34 |
35 | void JobClientAcquireHelper::acquire()
36 | {
37 | if (!m_semaphore->acquire()) {
38 | qWarning("QSystemSemaphore::acquire failed: %s (%d)",
39 | qPrintable(m_semaphore->errorString()), m_semaphore->error());
40 | return;
41 | }
42 | emit acquired();
43 | }
44 |
45 | } // namespace NMakeFile
46 |
--------------------------------------------------------------------------------
/src/jomlib/jobclientacquirehelper.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef JOBCLIENTACQUIRETHREAD_H
27 | #define JOBCLIENTACQUIRETHREAD_H
28 |
29 | #include
30 | #include
31 |
32 | namespace NMakeFile {
33 |
34 | class JobClientAcquireHelper : public QObject
35 | {
36 | Q_OBJECT
37 | public:
38 | explicit JobClientAcquireHelper(QSystemSemaphore *semaphore);
39 |
40 | public slots:
41 | void acquire();
42 |
43 | signals:
44 | void acquired();
45 |
46 | private:
47 | QSystemSemaphore *m_semaphore;
48 | };
49 |
50 | } // namespace NMakeFile
51 |
52 | #endif // JOBCLIENTACQUIRETHREAD_H
53 |
--------------------------------------------------------------------------------
/src/jomlib/jobserver.cpp:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #include "jobserver.h"
27 | #include "filetime.h"
28 | #include "helperfunctions.h"
29 | #include
30 | #include
31 | #include
32 |
33 | namespace NMakeFile {
34 |
35 | JobServer::JobServer(ProcessEnvironment *environment)
36 | : m_semaphore(0)
37 | , m_environment(environment)
38 | {
39 | }
40 |
41 | JobServer::~JobServer()
42 | {
43 | delete m_semaphore;
44 | }
45 |
46 | bool JobServer::start(int maxNumberOfJobs)
47 | {
48 | Q_ASSERT(m_environment);
49 |
50 | const quint64 randomId = (FileTime::currentTime().internalRepresentation() % UINT_MAX)
51 | ^ reinterpret_cast(&maxNumberOfJobs);
52 | const QString semaphoreKey = QLatin1String("jomsrv-")
53 | + QString::number(QCoreApplication::applicationPid()) + QLatin1Char('-')
54 | + QString::number(randomId);
55 | m_semaphore = new QSystemSemaphore(semaphoreKey, maxNumberOfJobs - 1, QSystemSemaphore::Create);
56 | if (m_semaphore->error() != QSystemSemaphore::NoError) {
57 | setError(m_semaphore->errorString());
58 | return false;
59 | }
60 | m_environment->insert(QLatin1String("_JOMSRVKEY_"), semaphoreKey);
61 | m_environment->insert(QLatin1String("_JOMJOBCOUNT_"), QString::number(maxNumberOfJobs));
62 | return true;
63 | }
64 |
65 | QString JobServer::errorString() const
66 | {
67 | return m_errorString;
68 | }
69 |
70 | void JobServer::setError(const QString &errorMessage)
71 | {
72 | m_errorString = errorMessage;
73 | }
74 |
75 | } // namespace NMakeFile
76 |
--------------------------------------------------------------------------------
/src/jomlib/jobserver.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef JOBSERVER_H
27 | #define JOBSERVER_H
28 |
29 | #include "processenvironment.h"
30 |
31 | QT_BEGIN_NAMESPACE
32 | class QSystemSemaphore;
33 | QT_END_NAMESPACE
34 |
35 | namespace NMakeFile {
36 |
37 | class JobServer
38 | {
39 | public:
40 | JobServer(ProcessEnvironment *environment);
41 | ~JobServer();
42 |
43 | bool start(int maxNumberOfJobs);
44 | QString errorString() const;
45 |
46 | private:
47 | void setError(const QString &errorMessage);
48 |
49 | QString m_errorString;
50 | QSystemSemaphore *m_semaphore;
51 | ProcessEnvironment *m_environment;
52 | };
53 |
54 | } // namespace NMakeFile
55 |
56 | #endif // JOBSERVER_H
57 |
--------------------------------------------------------------------------------
/src/jomlib/jomlib.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = lib
2 | TARGET = jomlib
3 | DESTDIR = ../../lib
4 | QT = core
5 | CONFIG += qt staticlib debug_and_release build_all
6 | DEFINES += _CRT_SECURE_NO_WARNINGS
7 | DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII
8 | PRECOMPILED_HEADER = stable.h
9 |
10 | build_pass:CONFIG(debug, debug|release) {
11 | TARGET = $$join(TARGET,,,d)
12 | }
13 |
14 | isEmpty(MSYSPATH):MSYSPATH=C:/msys
15 | !exists($$MSYSPATH): MSYSPATH=D:/msys
16 | !exists($$MSYSPATH): MSYSPATH=C:/msys64
17 | MSYS_BIN_PATHS = 1.0/bin usr/bin
18 | !exists($$MSYSPATH) {
19 | !build_pass:message("Can't locate path to MSYS. This is needed for flex.")
20 | } else {
21 | for(bin_path, MSYS_BIN_PATHS) {
22 | test_flex_bin = $$MSYSPATH/$$bin_path/flex.exe
23 | exists($$test_flex_bin):FLEX_BIN = $$test_flex_bin
24 | }
25 | isEmpty(FLEX_BIN) {
26 | !build_pass:message("MSYSPATH is set but flex cannot be found.")
27 | }
28 | }
29 | !isEmpty(FLEX_BIN) {
30 | # One special extra compiler for ppexpr.l because
31 | # msys flex does not understand backslashes and I have no way
32 | # to translate the slashes in ${QMAKE_FILE_IN}. /me rolls eyes...
33 | PPEXPR_FLEX_FILE = $$PWD/ppexpr.l
34 | flex.name = flex ppexpr.l
35 | flex.input = PPEXPR_FLEX_FILE
36 | flex.output = ${QMAKE_FILE_BASE}-lex.inc
37 | flex.commands = $$FLEX_BIN --noline $$PPEXPR_FLEX_FILE
38 | flex.CONFIG += no_link explicit_dependencies
39 | QMAKE_EXTRA_COMPILERS += flex
40 |
41 | QLALR_FILES = ppexpr.g
42 | qlalr.name = qlalr
43 | qlalr.input = QLALR_FILES
44 | qlalr.output = ${QMAKE_FILE_BASE}_grammar.cpp
45 | qlalr.commands = $$[QT_INSTALL_BINS]\\qlalr.exe --no-lines ${QMAKE_FILE_IN}
46 | qlalr.depends = $$PWD/${QMAKE_FILE_BASE}.l
47 | qlalr.dependency_type = TYPE_C
48 | qlalr.CONFIG += no_link explicit_dependencies
49 | QMAKE_EXTRA_COMPILERS += qlalr
50 | }
51 |
52 | win32-* {
53 | HEADERS += \
54 | iocompletionport.h
55 | SOURCES += \
56 | jomprocess.cpp \
57 | iocompletionport.cpp
58 | } else {
59 | DEFINES += USE_QPROCESS
60 | SOURCES += \
61 | jomprocess_qt.cpp
62 | }
63 |
64 | HEADERS += \
65 | fastfileinfo.h \
66 | filetime.h \
67 | helperfunctions.h \
68 | jobserver.h \
69 | makefile.h \
70 | makefilefactory.h \
71 | makefilelinereader.h \
72 | macrotable.h \
73 | exception.h \
74 | dependencygraph.h \
75 | options.h \
76 | parser.h \
77 | preprocessor.h \
78 | ppexprparser.h \
79 | targetexecutor.h \
80 | commandexecutor.h \
81 | jomprocess.h \
82 | processenvironment.h \
83 | jobclient.h \
84 | jobclientacquirehelper.h
85 |
86 | SOURCES += \
87 | fastfileinfo.cpp \
88 | filetime.cpp \
89 | helperfunctions.cpp \
90 | jobserver.cpp \
91 | macrotable.cpp \
92 | makefile.cpp \
93 | makefilefactory.cpp \
94 | makefilelinereader.cpp \
95 | exception.cpp \
96 | dependencygraph.cpp \
97 | options.cpp \
98 | parser.cpp \
99 | preprocessor.cpp \
100 | ppexpr_grammar.cpp \
101 | ppexprparser.cpp \
102 | targetexecutor.cpp \
103 | commandexecutor.cpp \
104 | jobclient.cpp \
105 | jobclientacquirehelper.cpp
106 |
107 | OTHER_FILES += \
108 | ppexpr.g \
109 | ppexpr.l
110 |
--------------------------------------------------------------------------------
/src/jomlib/jomprocess.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef PROCESS_H
27 | #define PROCESS_H
28 |
29 | #include "processenvironment.h"
30 | #include
31 | #include
32 |
33 | #ifdef USE_QPROCESS
34 |
35 | #include
36 |
37 | namespace NMakeFile {
38 |
39 | class Process : public QProcess
40 | {
41 | Q_OBJECT
42 | public:
43 | enum ProcessError
44 | {
45 | UnknownError,
46 | FailedToStart,
47 | Crashed
48 | };
49 |
50 | enum ExitStatus
51 | {
52 | NormalExit,
53 | CrashExit
54 | };
55 |
56 | Process(QObject *parent = 0);
57 | void setBufferedOutput(bool bufferedOutput);
58 | bool isBufferedOutputSet() const;
59 | void setEnvironment(const ProcessEnvironment &e);
60 | ProcessEnvironment environment() const;
61 | bool isRunning() const;
62 | void start(const QString &commandLine);
63 | void writeToStdOutBuffer(const QByteArray &output);
64 | void writeToStdErrBuffer(const QByteArray &output);
65 | ExitStatus exitStatus() const;
66 |
67 | signals:
68 | void error(Process::ProcessError);
69 | void finished(int, Process::ExitStatus);
70 |
71 | private slots:
72 | void forwardError(QProcess::ProcessError);
73 | void forwardFinished(int, QProcess::ExitStatus);
74 | };
75 |
76 | } // namespace NMakeFile
77 |
78 | #else
79 |
80 | namespace NMakeFile {
81 |
82 | class Process : public QObject
83 | {
84 | Q_OBJECT
85 | public:
86 | explicit Process(QObject *parent = 0);
87 | ~Process();
88 |
89 | enum ProcessError
90 | {
91 | UnknownError,
92 | FailedToStart,
93 | Crashed
94 | };
95 |
96 | enum ExitStatus
97 | {
98 | NormalExit,
99 | CrashExit
100 | };
101 |
102 | enum ProcessState
103 | {
104 | NotRunning,
105 | Starting,
106 | Running
107 | };
108 |
109 | void setBufferedOutput(bool b);
110 | bool isBufferedOutputSet() const { return m_bufferedOutput; }
111 | void writeToStdOutBuffer(const QByteArray &output);
112 | void writeToStdErrBuffer(const QByteArray &output);
113 | void setWorkingDirectory(const QString &path);
114 | const QString &workingDirectory() const { return m_workingDirectory; }
115 | void setEnvironment(const ProcessEnvironment &environment);
116 | const ProcessEnvironment &environment() const { return m_environment; }
117 | int exitCode() const { return m_exitCode; }
118 | ExitStatus exitStatus() const { return m_exitStatus; }
119 | bool isRunning() const { return m_state == Running; }
120 |
121 | signals:
122 | void error(Process::ProcessError);
123 | void finished(int, Process::ExitStatus);
124 |
125 | public slots:
126 | void start(const QString &commandLine);
127 | bool waitForFinished();
128 |
129 | private:
130 | void printBufferedOutput();
131 |
132 | private slots:
133 | void tryToRetrieveExitCode();
134 | void onProcessFinished();
135 |
136 | private:
137 | class ProcessPrivate *d;
138 | QString m_workingDirectory;
139 | ProcessEnvironment m_environment;
140 | QByteArray m_envBlock;
141 | ProcessState m_state;
142 | int m_exitCode;
143 | ExitStatus m_exitStatus;
144 | bool m_bufferedOutput;
145 |
146 | friend class ProcessPrivate;
147 | };
148 |
149 | } // namespace NMakeFile
150 |
151 | #endif // USE_QPROCESS
152 |
153 | #endif // PROCESS_H
154 |
--------------------------------------------------------------------------------
/src/jomlib/jomprocess_qt.cpp:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #include "jomprocess.h"
27 | #include
28 |
29 | namespace NMakeFile {
30 |
31 | Process::Process(QObject *parent)
32 | : QProcess(parent)
33 | {
34 | connect(this, SIGNAL(error(QProcess::ProcessError)), SLOT(forwardError(QProcess::ProcessError)));
35 | connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(forwardFinished(int, QProcess::ExitStatus)));
36 | }
37 |
38 | void Process::setBufferedOutput(bool bufferedOutput)
39 | {
40 | QProcess::setProcessChannelMode(bufferedOutput ? SeparateChannels : ForwardedChannels);
41 | }
42 |
43 | bool Process::isBufferedOutputSet() const
44 | {
45 | return QProcess::processChannelMode() == SeparateChannels;
46 | }
47 |
48 | void Process::setEnvironment(const ProcessEnvironment &e)
49 | {
50 | QProcessEnvironment qpenv;
51 | for (ProcessEnvironment::const_iterator it = e.constBegin(); it != e.constEnd(); ++it)
52 | qpenv.insert(it.key().toQString(), it.value());
53 | QProcess::setProcessEnvironment(qpenv);
54 | }
55 |
56 | ProcessEnvironment Process::environment() const
57 | {
58 | ProcessEnvironment env;
59 | const QProcessEnvironment qpenv = QProcess::processEnvironment();
60 | foreach (const QString &key, qpenv.keys())
61 | env.insert(key, qpenv.value(key));
62 | return env;
63 | }
64 |
65 | bool Process::isRunning() const
66 | {
67 | return QProcess::state() == QProcess::Running;
68 | }
69 |
70 | void Process::start(const QString &commandLine)
71 | {
72 | QProcess::start(commandLine);
73 | QProcess::waitForStarted();
74 | }
75 |
76 | void Process::writeToStdOutBuffer(const QByteArray &output)
77 | {
78 | fputs(output.data(), stdout);
79 | fflush(stdout);
80 | }
81 |
82 | void Process::writeToStdErrBuffer(const QByteArray &output)
83 | {
84 | fputs(output.data(), stderr);
85 | fflush(stderr);
86 | }
87 |
88 | Process::ExitStatus Process::exitStatus() const
89 | {
90 | return static_cast(QProcess::exitStatus());
91 | }
92 |
93 | void Process::forwardError(QProcess::ProcessError qe)
94 | {
95 | ProcessError e;
96 | switch (qe) {
97 | case QProcess::FailedToStart:
98 | e = FailedToStart;
99 | break;
100 | case QProcess::Crashed:
101 | e = Crashed;
102 | break;
103 | default:
104 | e = UnknownError;
105 | }
106 | emit error(e);
107 | }
108 |
109 | void Process::forwardFinished(int exitCode, QProcess::ExitStatus status)
110 | {
111 | emit finished(exitCode, static_cast(status));
112 | }
113 |
114 | } // namespace NMakeFile
115 |
--------------------------------------------------------------------------------
/src/jomlib/macrotable.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef MACROTABLE_H
27 | #define MACROTABLE_H
28 |
29 | #include "processenvironment.h"
30 |
31 | #include
32 | #include
33 |
34 | namespace NMakeFile {
35 |
36 | class MacroTable
37 | {
38 | public:
39 | static const QChar fileNameMacroMagicEscape;
40 |
41 | MacroTable();
42 | ~MacroTable();
43 |
44 | void setEnvironment(const ProcessEnvironment &e) { m_environment = e; }
45 | const ProcessEnvironment &environment() const { return m_environment; }
46 |
47 | bool isMacroDefined(const QString& name) const;
48 | bool isMacroNameValid(const QString& name) const;
49 | QString macroValue(const QString& macroName) const;
50 | void defineEnvironmentMacroValue(const QString& name, const QString& value, bool readOnly = false);
51 | void defineCommandLineMacroValue(const QString &name, const QString &value);
52 | void defineImplicitCommandLineMacroValue(const QString &name, const QString &value);
53 | void setMacroValue(const QString& name, const QString& value);
54 | void setMacroValue(const char *szStr, const QString& value) { setMacroValue(QString::fromLatin1(szStr), value); }
55 | void setMacroValue(const char *szStr, const char *szValue) { setMacroValue(QString::fromLatin1(szStr), QString::fromLatin1(szValue)); }
56 | void predefineValue(const QString &name, const QString &value);
57 | void predefineValue(const char *szStr, const QString &value) { predefineValue(QString::fromLatin1(szStr), value); }
58 | void predefineValue(const char *szStr, const char *szValue) { predefineValue(QString::fromLatin1(szStr), QString::fromLatin1(szValue)); }
59 | void undefineMacro(const QString& name);
60 | QString expandMacros(const QString& str, bool inDependentsLine = false) const;
61 | void dump() const;
62 |
63 | struct Substitution
64 | {
65 | QString before;
66 | QString after;
67 | };
68 |
69 | static Substitution parseSubstitutionStatement(const QString &str, int substitutionStartIdx, int ¯oInvokationEndIdx);
70 | static void applySubstitution(const Substitution &substitution, QString &value);
71 |
72 | private:
73 | enum class MacroSource
74 | {
75 | CommandLine,
76 | CommandLineImplicit,
77 | MakeFile,
78 | Environment,
79 | Predefinition
80 | };
81 |
82 | struct MacroData
83 | {
84 | MacroSource source = MacroSource::MakeFile;
85 | bool isReadOnly = false;
86 | QString value;
87 | };
88 |
89 | void setMacroValueImpl(const QString &name, const QString &value, MacroSource source);
90 | void defineCommandLineMacroValueImpl(const QString &name, const QString &value,
91 | MacroSource source);
92 | MacroData* internalSetMacroValue(const QString &name, const QString &value,
93 | bool ignoreReadOnly = false);
94 | void setEnvironmentVariable(const QString& name, const QString& value);
95 | QString expandMacros(const QString& str, bool inDependentsLine, QSet& usedMacros) const;
96 | QString cycleCheckedMacroValue(const QString& macroName, QSet& usedMacros) const;
97 |
98 | QHash m_macros;
99 | ProcessEnvironment m_environment;
100 | };
101 |
102 | } // namespace NMakeFile
103 |
104 | #endif // MACROTABLE_H
105 |
--------------------------------------------------------------------------------
/src/jomlib/makefile.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef MAKEFILE_H
27 | #define MAKEFILE_H
28 |
29 | #include "fastfileinfo.h"
30 | #include "macrotable.h"
31 | #include
32 | #include
33 | #include
34 |
35 | namespace NMakeFile {
36 |
37 | class Options;
38 |
39 | class InlineFile {
40 | public:
41 | InlineFile();
42 | InlineFile(const InlineFile& rhs);
43 |
44 | bool m_keep;
45 | bool m_unicode;
46 | QString m_filename; // optional
47 | QString m_content;
48 | };
49 |
50 | class Command {
51 | public:
52 | Command();
53 | Command(const Command& rhs);
54 | ~Command();
55 |
56 | void evaluateModifiers();
57 |
58 | QString m_commandLine;
59 | QList m_inlineFiles;
60 | unsigned int m_maxExitCode; // greatest allowed exit code
61 | bool m_silent;
62 | bool m_singleExecution; // Execute this command for each dependent, if the command contains $** or $?.
63 | };
64 |
65 | class CommandContainer {
66 | public:
67 | CommandContainer() {};
68 | CommandContainer(const CommandContainer& rhs)
69 | : m_commands(rhs.m_commands)
70 | {}
71 |
72 | QList m_commands;
73 | };
74 |
75 | class CommandExecutor;
76 | class InferenceRule;
77 | class Makefile;
78 |
79 | class DescriptionBlock : public CommandContainer {
80 | public:
81 | DescriptionBlock(Makefile* mkfile);
82 |
83 | void expandFileNameMacrosForDependents();
84 | void expandFileNameMacros();
85 |
86 | void setTargetName(const QString& name);
87 |
88 | /**
89 | * Returns the name of the target.
90 | * This string may be surrounded by double quotes!
91 | */
92 | QString targetName() const
93 | {
94 | return m_targetName;
95 | }
96 |
97 | /**
98 | * Returns the makefile, this target belongs to.
99 | */
100 | Makefile* makefile() const { return m_pMakefile; }
101 |
102 | QStringList m_dependents;
103 | FileTime m_timeStamp;
104 | bool m_bFileExists;
105 | bool m_bVisitedByCycleCheck;
106 | bool m_bNoCyclesRootedHere;
107 | QVector m_inferenceRules;
108 |
109 | enum AddCommandsState { ACSUnknown, ACSEnabled, ACSDisabled };
110 | AddCommandsState m_canAddCommands;
111 |
112 | private:
113 | void expandFileNameMacros(Command& command, int depIdx);
114 | void expandFileNameMacros(QString& str, int depIdx, bool dependentsForbidden);
115 | QStringList getFileNameMacroValues(const QStringRef& str, int& replacementLength, int depIdx,
116 | bool dependentsForbidden);
117 |
118 | private:
119 | QString m_targetName;
120 | Makefile* m_pMakefile;
121 | };
122 |
123 | class InferenceRule : public CommandContainer {
124 | public:
125 | InferenceRule();
126 | InferenceRule(const InferenceRule& rhs);
127 |
128 | bool operator == (const InferenceRule& rhs) const;
129 |
130 | QString inferredDependent(const QString &targetName) const;
131 |
132 | bool m_batchMode;
133 | QString m_fromSearchPath;
134 | QString m_fromExtension;
135 | QString m_toSearchPath;
136 | QString m_toExtension;
137 | int m_priority; // priority < 0 means: not applicable
138 | };
139 |
140 | class Makefile
141 | {
142 | public:
143 | Makefile(const QString &fileName);
144 | ~Makefile();
145 |
146 | void clear();
147 |
148 | void append(DescriptionBlock* target)
149 | {
150 | m_targets[target->targetName().toLower()] = target;
151 | if (!m_firstTarget) m_firstTarget = target;
152 | }
153 |
154 | DescriptionBlock* firstTarget()
155 | {
156 | return m_firstTarget;
157 | }
158 |
159 | DescriptionBlock* target(const QString& name) const
160 | {
161 | DescriptionBlock* result = 0;
162 | const QString lowerName = name.toLower();
163 | result = m_targets.value(lowerName, 0);
164 | if (result)
165 | return result;
166 |
167 | QString systemName = lowerName;
168 | result = m_targets.value(systemName.replace(QLatin1Char('/'), QLatin1Char('\\')), 0);
169 | if (result)
170 | return result;
171 |
172 | return result;
173 | }
174 |
175 | const QHash& targets() const
176 | {
177 | return m_targets;
178 | }
179 |
180 | const QStringList& preciousTargets() const
181 | {
182 | return m_preciousTargets;
183 | }
184 |
185 | const QVector& inferenceRules() const
186 | {
187 | return m_inferenceRules;
188 | }
189 |
190 | const QString &fileName() const { return m_fileName; }
191 | const QString &dirPath() const;
192 | void setOptions(Options *o) { m_options = o; }
193 | const Options* options() const { return m_options; }
194 | void setParallelExecutionDisabled(bool disabled) { m_parallelExecutionDisabled = disabled; }
195 | bool isParallelExecutionDisabled() const { return m_parallelExecutionDisabled; }
196 |
197 | void setMacroTable(MacroTable *mt) { m_macroTable = mt; }
198 | const MacroTable* macroTable() const { return m_macroTable; }
199 |
200 | void dumpTarget(DescriptionBlock*, uchar level = 0) const;
201 | void dumpTargets() const;
202 | void dumpInferenceRules() const;
203 | void invalidateTimeStamps();
204 | void applyInferenceRules(QList targets);
205 | void addInferenceRule(InferenceRule *rule);
206 | void calculateInferenceRulePriorities(const QStringList &suffixes);
207 | void addPreciousTarget(const QString& targetName);
208 |
209 | private:
210 | void filterRulesByDependent(QVector& rules, const QString& targetName);
211 | QStringList findInferredDependents(InferenceRule* rule, const QStringList& dependents);
212 | void applyInferenceRules(DescriptionBlock* target);
213 | void applyInferenceRule(DescriptionBlock* target, const InferenceRule *rule, bool applyingBatchMode = false);
214 | void applyInferenceRule(QList &batch, const InferenceRule *rule);
215 |
216 | private:
217 | QString m_fileName;
218 | mutable QString m_dirPath;
219 | DescriptionBlock* m_firstTarget;
220 | QHash m_targets;
221 | QStringList m_preciousTargets;
222 | QVector m_inferenceRules;
223 | MacroTable* m_macroTable;
224 | Options* m_options;
225 | QSet m_batchModeRules;
226 | QMultiHash m_batchModeTargets;
227 | bool m_parallelExecutionDisabled;
228 | };
229 |
230 | } // namespace NMakeFile
231 |
232 | #endif // MAKEFILE_H
233 |
--------------------------------------------------------------------------------
/src/jomlib/makefilefactory.cpp:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #include "exception.h"
27 | #include "makefilefactory.h"
28 | #include "macrotable.h"
29 | #include "makefile.h"
30 | #include "options.h"
31 | #include "parser.h"
32 | #include "preprocessor.h"
33 |
34 | #include
35 | #include
36 |
37 | namespace NMakeFile {
38 |
39 | MakefileFactory::MakefileFactory()
40 | : m_makefile(0),
41 | m_errorType(NoError)
42 | {
43 | }
44 |
45 | void MakefileFactory::setEnvironment(const QStringList &env)
46 | {
47 | for (QStringList::const_iterator it = env.begin(); it != env.end(); ++it) {
48 | int idx = it->indexOf(QLatin1Char('='));
49 | if (idx >= 0)
50 | m_environment.insert(it->left(idx), it->mid(idx + 1));
51 | }
52 | }
53 |
54 | void MakefileFactory::clear()
55 | {
56 | m_makefile = 0;
57 | m_errorType = NoError;
58 | m_errorString.clear();
59 | m_activeTargets.clear();
60 | }
61 |
62 | static void readEnvironment(const ProcessEnvironment &environment, MacroTable *macroTable, bool forceReadOnly)
63 | {
64 | ProcessEnvironment::const_iterator it = environment.begin();
65 | for (; it != environment.end(); ++it)
66 | macroTable->defineEnvironmentMacroValue(it.key().toQString(), it.value(), forceReadOnly);
67 | }
68 |
69 | /**
70 | * Returns true, if the path contains some whitespace.
71 | */
72 | static bool isComplexPathName(const QString& path)
73 | {
74 | for (int i=path.length()-1; i > 0; i--) {
75 | const QChar ch = path.at(i);
76 | if (ch.isSpace())
77 | return true;
78 | }
79 | return false;
80 | }
81 |
82 | /**
83 | * Enclose the path in double quotes, if its a complex one.
84 | */
85 | static QString encloseInDoubleQuotesIfNeeded(const QString& path)
86 | {
87 | if (isComplexPathName(path)) {
88 | QString result(QLatin1Char('"'));
89 | result.append(path);
90 | result.append(QLatin1Char('"'));
91 | return result;
92 | }
93 | return path;
94 | }
95 |
96 | bool MakefileFactory::apply(const QStringList& commandLineArguments, Options **outopt)
97 | {
98 | if (m_makefile)
99 | clear();
100 |
101 | Options *options = new Options;
102 | if (outopt)
103 | *outopt = options;
104 | MacroTable *macroTable = new MacroTable;
105 | macroTable->setEnvironment(m_environment);
106 |
107 | QString filename;
108 | if (!options->readCommandLineArguments(commandLineArguments, filename, m_activeTargets, *macroTable)) {
109 | m_errorType = CommandLineError;
110 | return false;
111 | }
112 | if (options->showUsageAndExit || options->showVersionAndExit)
113 | return true;
114 |
115 | if (!options->stderrFile.isEmpty()) {
116 | // Try to open the file for writing.
117 | const wchar_t *wszFileName = reinterpret_cast(options->stderrFile.utf16());
118 | FILE *f = _wfopen(wszFileName, L"w");
119 | if (!f) {
120 | m_errorString = QLatin1String("Cannot open stderr file for writing.");
121 | m_errorType = IOError;
122 | return false;
123 | }
124 | fclose(f);
125 | if (!_wfreopen(wszFileName, L"w", stderr)) {
126 | m_errorString = QLatin1String("Cannot reopen stderr handle for writing.");
127 | m_errorType = IOError;
128 | return false;
129 | }
130 | }
131 |
132 | options->fullAppPath = QDir::toNativeSeparators(QCoreApplication::applicationFilePath());
133 |
134 | readEnvironment(m_environment, macroTable, options->overrideEnvVarMacros);
135 | if (!options->ignorePredefinedRulesAndMacros) {
136 | macroTable->predefineValue("MAKE", encloseInDoubleQuotesIfNeeded(options->fullAppPath));
137 | macroTable->predefineValue("MAKEDIR", encloseInDoubleQuotesIfNeeded(
138 | QDir::toNativeSeparators(QDir::currentPath())));
139 | macroTable->predefineValue("AS", "ml"); // Macro Assembler
140 | macroTable->predefineValue("ASFLAGS", QString());
141 | macroTable->predefineValue("BC", "bc"); // Basic Compiler
142 | macroTable->predefineValue("BCFLAGS", QString());
143 | macroTable->predefineValue("CC", "cl"); // C Compiler
144 | macroTable->predefineValue("CCFLAGS", QString());
145 | macroTable->predefineValue("COBOL", "cobol"); // COBOL Compiler
146 | macroTable->predefineValue("COBOLFLAGS", QString());
147 | macroTable->predefineValue("CPP", "cl"); // C++ Compiler
148 | macroTable->predefineValue("CPPFLAGS", QString());
149 | macroTable->predefineValue("CXX", "cl"); // C++ Compiler
150 | macroTable->predefineValue("CXXFLAGS", QString());
151 | macroTable->predefineValue("FOR", "fl"); // FORTRAN Compiler
152 | macroTable->predefineValue("FORFLAGS", QString());
153 | macroTable->predefineValue("PASCAL", "pl"); // Pascal Compiler
154 | macroTable->predefineValue("PASCALFLAGS", QString());
155 | macroTable->predefineValue("RC", "rc"); // Resource Compiler
156 | macroTable->predefineValue("RCFLAGS", QString());
157 | }
158 |
159 | try {
160 | m_makefile = new Makefile(filename);
161 | m_makefile->setOptions(options);
162 | m_makefile->setMacroTable(macroTable);
163 | Preprocessor preprocessor;
164 | preprocessor.setMacroTable(macroTable);
165 | preprocessor.openFile(filename);
166 | Parser parser;
167 | parser.apply(&preprocessor, m_makefile, m_activeTargets);
168 | } catch (Exception &e) {
169 | m_errorType = ParserError;
170 | m_errorString = e.toString();
171 | }
172 |
173 | return m_errorType == NoError;
174 | }
175 |
176 | } //namespace NMakeFile
177 |
--------------------------------------------------------------------------------
/src/jomlib/makefilefactory.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef MAKEFILEFACTORY_H
27 | #define MAKEFILEFACTORY_H
28 |
29 | #include "processenvironment.h"
30 | #include
31 |
32 | namespace NMakeFile {
33 |
34 | class Makefile;
35 | class Options;
36 |
37 | class MakefileFactory
38 | {
39 | public:
40 | MakefileFactory();
41 | void setEnvironment(const QStringList& env);
42 | bool apply(const QStringList& commandLineArguments, Options **outopt = 0);
43 |
44 | enum ErrorType {
45 | NoError,
46 | CommandLineError,
47 | ParserError,
48 | IOError
49 | };
50 |
51 | Makefile* makefile() { return m_makefile; }
52 | const QStringList& activeTargets() const { return m_activeTargets; }
53 | const QString& errorString() const { return m_errorString; }
54 | ErrorType errorType() const { return m_errorType; }
55 |
56 | private:
57 | void clear();
58 |
59 | private:
60 | Makefile* m_makefile;
61 | ProcessEnvironment m_environment;
62 | QStringList m_activeTargets;
63 | QString m_errorString;
64 | ErrorType m_errorType;
65 | };
66 |
67 | } // namespace NMakeFile
68 |
69 | #endif // MAKEFILEFACTORY_H
70 |
--------------------------------------------------------------------------------
/src/jomlib/makefilelinereader.cpp:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #include "makefilelinereader.h"
27 | #include "helperfunctions.h"
28 | #include
29 | #include
30 |
31 | namespace NMakeFile {
32 |
33 | MakefileLineReader::MakefileLineReader(const QString& filename)
34 | : m_file(filename),
35 | m_nLineBufferSize(m_nInitialLineBufferSize),
36 | m_nLineNumber(0)
37 | {
38 | m_lineBuffer = reinterpret_cast( malloc(m_nLineBufferSize) );
39 | }
40 |
41 | MakefileLineReader::~MakefileLineReader()
42 | {
43 | close();
44 | free(m_lineBuffer);
45 | }
46 |
47 | bool MakefileLineReader::open()
48 | {
49 | if (!m_file.open(QIODevice::ReadOnly | QIODevice::Text))
50 | return false;
51 |
52 | // check BOM
53 | enum FileEncoding { FCLatin1, FCUTF8, FCUTF16 };
54 | FileEncoding fileEncoding = FCLatin1;
55 | QByteArray buf = m_file.peek(3);
56 | if (buf.startsWith("\xFF\xFE"))
57 | fileEncoding = FCUTF16;
58 | else if (buf.startsWith("\xEF\xBB\xBF"))
59 | fileEncoding = FCUTF8;
60 |
61 | if (fileEncoding == FCLatin1) {
62 | m_readLineImpl = &NMakeFile::MakefileLineReader::readLine_impl_local8bit;
63 | } else {
64 | m_readLineImpl = &NMakeFile::MakefileLineReader::readLine_impl_unicode;
65 | m_textStream.setCodec(fileEncoding == FCUTF8 ? "UTF-8" : "UTF-16");
66 | m_textStream.setAutoDetectUnicode(false);
67 | m_textStream.setDevice(&m_file);
68 | }
69 |
70 | return true;
71 | }
72 |
73 | void MakefileLineReader::close()
74 | {
75 | m_file.close();
76 | }
77 |
78 | void MakefileLineReader::growLineBuffer(size_t nGrow)
79 | {
80 | //fprintf(stderr, "realloc %d -> %d\n", m_nLineBufferSize, m_nLineBufferSize + nGrow);
81 | m_nLineBufferSize += nGrow;
82 | m_lineBuffer = reinterpret_cast(realloc(m_lineBuffer, m_nLineBufferSize));
83 | }
84 |
85 | /**
86 | * This function reads lines from a makefile and
87 | * - ignores all lines that start with #
88 | * - combines multi-lines (lines with \ at the end) into a single long line
89 | * - handles the ^ escape character for \ and \n at the end
90 | */
91 | MakefileLine MakefileLineReader::readLine(bool bInlineFileMode)
92 | {
93 | if (bInlineFileMode) {
94 | m_nLineNumber++;
95 | return MakefileLine{ QString::fromLatin1(m_file.readLine()) };
96 | }
97 |
98 | return (this->*m_readLineImpl)();
99 | }
100 |
101 | /**
102 | * readLine implementation optimized for 8 bit files.
103 | */
104 | MakefileLine MakefileLineReader::readLine_impl_local8bit()
105 | {
106 | size_t bytesRead;
107 | do {
108 | m_nLineNumber++;
109 | const qint64 n = m_file.readLine(m_lineBuffer, m_nLineBufferSize - 1);
110 | if (n <= 0)
111 | return {};
112 |
113 | bytesRead = n;
114 | while (m_lineBuffer[bytesRead - 1] != '\n') {
115 | if (m_file.atEnd()) {
116 | // The file didn't end with a newline.
117 | // Code below relies on having a trailing newline.
118 | // We're imitating it by increasing the string length.
119 | if (bytesRead >= (m_nLineBufferSize - 2))
120 | growLineBuffer(1);
121 | ++bytesRead;
122 | break;
123 | }
124 |
125 | growLineBuffer(m_nLineBufferGrowSize);
126 | int moreBytesRead = m_file.readLine(m_lineBuffer + bytesRead, m_nLineBufferSize - 1 - bytesRead);
127 | if (moreBytesRead <= 0)
128 | break;
129 | bytesRead += moreBytesRead;
130 | }
131 |
132 | } while (m_lineBuffer[0] == '#');
133 | m_lineBuffer[bytesRead] = '\0';
134 |
135 | MakefileLine line;
136 | char* buf = m_lineBuffer;
137 | int bufLength = static_cast(bytesRead);
138 | if (bufLength >= 2 && buf[bufLength - 2] == '\\') {
139 | if (bufLength >= 3 && buf[bufLength - 3] == '^') {
140 | buf[bufLength - 3] = '\\'; // replace "^\\\n" -> "\\\\\n"
141 | bufLength -= 2; // remove "\\\n"
142 | } else if (bufLength >= 3 && buf[bufLength - 3] == '\\') {
143 | bufLength--; // remove trailing \n
144 | } else {
145 | bufLength -= 2; // remove "\\\n"
146 | line.continuation = LineContinuationType::Backslash;
147 | }
148 | } else if (bufLength >= 2 && buf[bufLength - 2] == '^') {
149 | bufLength -= 2;
150 | line.continuation = LineContinuationType::Caret;
151 | } else {
152 | bufLength--; // remove trailing \n
153 | }
154 |
155 | line.content = QString::fromLatin1(buf, bufLength);
156 | return line;
157 | }
158 |
159 | /**
160 | * readLine implementation for unicode files.
161 | * Much slower than the 8 bit version.
162 | */
163 | MakefileLine MakefileLineReader::readLine_impl_unicode()
164 | {
165 | MakefileLine line;
166 | QString str;
167 | do {
168 | m_nLineNumber++;
169 | str = m_textStream.readLine();
170 | } while (str.startsWith(QLatin1Char('#')));
171 |
172 | if (str.isNull())
173 | return line;
174 |
175 | if (str.endsWith(QLatin1String("^\\"))) {
176 | str.remove(str.length() - 2, 1);
177 | } else if (str.endsWith(QLatin1String("\\\\"))) {
178 | // Do nothing. Double backslash at the end is not altered.
179 | } else if (str.endsWith(QLatin1Char('\\'))) {
180 | str.chop(1);
181 | line.continuation = LineContinuationType::Backslash;
182 | } else if (str.endsWith(QLatin1Char('^'))) {
183 | str.chop(1);
184 | line.continuation = LineContinuationType::Caret;
185 | }
186 |
187 | line.content = str;
188 | return line;
189 | }
190 |
191 | } // namespace NMakeFile
192 |
--------------------------------------------------------------------------------
/src/jomlib/makefilelinereader.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef MAKEFILELINEREADER_H
27 | #define MAKEFILELINEREADER_H
28 |
29 | #include
30 | #include
31 |
32 | namespace NMakeFile {
33 |
34 | enum class LineContinuationType
35 | {
36 | None,
37 | Backslash,
38 | Caret
39 | };
40 |
41 | struct MakefileLine
42 | {
43 | QString content;
44 | LineContinuationType continuation = LineContinuationType::None;
45 | };
46 |
47 | inline bool isComplete(const MakefileLine &line)
48 | {
49 | return line.continuation == LineContinuationType::None;
50 | }
51 |
52 | class MakefileLineReader {
53 | public:
54 | MakefileLineReader(const QString& filename);
55 | ~MakefileLineReader();
56 |
57 | bool open();
58 | void close();
59 | MakefileLine readLine(bool bInlineFileMode);
60 | QString fileName() const { return m_file.fileName(); }
61 | uint lineNumber() const { return m_nLineNumber; }
62 |
63 | private:
64 | void growLineBuffer(size_t nGrow);
65 |
66 | typedef MakefileLine (MakefileLineReader::*ReadLineImpl)();
67 | ReadLineImpl m_readLineImpl;
68 | MakefileLine readLine_impl_local8bit();
69 | MakefileLine readLine_impl_unicode();
70 |
71 | private:
72 | QFile m_file;
73 | QTextStream m_textStream;
74 | static const size_t m_nInitialLineBufferSize = 6144;
75 | static const size_t m_nLineBufferGrowSize = 1024;
76 | size_t m_nLineBufferSize;
77 | char *m_lineBuffer;
78 | uint m_nLineNumber;
79 | };
80 |
81 | } // namespace NMakeFile
82 |
83 | #endif // MAKEFILELINEREADER_H
84 |
--------------------------------------------------------------------------------
/src/jomlib/options.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef OPTIONS_H
27 | #define OPTIONS_H
28 |
29 | #include
30 | #include
31 |
32 | namespace NMakeFile {
33 |
34 | class MacroTable;
35 |
36 | class Options
37 | {
38 | public:
39 | Options();
40 |
41 | bool readCommandLineArguments(QStringList arguments, QString& makefile,
42 | QStringList& targets, MacroTable& macroTable);
43 |
44 | bool buildAllTargets;
45 | bool buildIfTimeStampsAreEqual;
46 | bool showLogo;
47 | bool suppressOutputMessages;
48 | bool overrideEnvVarMacros;
49 | bool displayIncludeFileNames;
50 | bool dryRun;
51 | bool stopOnErrors;
52 | bool buildUnrelatedTargetsOnError;
53 | bool checkTimeStampsButDoNotBuild;
54 | bool changeTimeStampsButDoNotBuild;
55 | bool ignorePredefinedRulesAndMacros;
56 | bool suppressExecutedCommandsDisplay;
57 | bool printWorkingDir;
58 | bool batchModeEnabled;
59 | bool dumpInlineFiles;
60 | bool dumpDependencyGraph;
61 | bool dumpDependencyGraphDot;
62 | bool displayMakeInformation;
63 | bool showUsageAndExit;
64 | bool displayBuildInfo;
65 | bool debugMode;
66 | bool showVersionAndExit;
67 | QString fullAppPath;
68 | QString stderrFile;
69 |
70 | private:
71 | bool expandCommandFiles(QStringList& arguments);
72 | bool handleCommandLineOption(const QStringList &originalArguments, QString arg, QStringList& arguments, QString& makefile, QString& makeflags);
73 | };
74 |
75 | class GlobalOptions
76 | {
77 | public:
78 | GlobalOptions();
79 | int maxNumberOfJobs;
80 | bool isMaxNumberOfJobsSet;
81 | };
82 |
83 | extern GlobalOptions g_options;
84 |
85 | } // namespace NMakeFile
86 |
87 | #endif // OPTIONS_H
88 |
--------------------------------------------------------------------------------
/src/jomlib/parser.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef PARSER_H
27 | #define PARSER_H
28 |
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 |
35 | #include "makefile.h"
36 |
37 | namespace NMakeFile {
38 |
39 | class Preprocessor;
40 | class PPExpression;
41 |
42 | class Parser
43 | {
44 | public:
45 | Parser();
46 | virtual ~Parser();
47 |
48 | void apply(Preprocessor* pp,
49 | Makefile* mkfile,
50 | const QStringList& activeTargets = QStringList());
51 | MacroTable* macroTable();
52 |
53 | private:
54 | void readLine();
55 | bool isEmptyLine(const QString& line);
56 | bool isDescriptionBlock(int& separatorPos, int& separatorLength, int& commandSeparatorPos);
57 | bool isInferenceRule(const QString& line);
58 | bool isDotDirective(const QString& line);
59 | DescriptionBlock* createTarget(const QString& targetName);
60 | void parseDescriptionBlock(int separatorPos, int separatorLength, int commandSeparatorPos);
61 | void parseInferenceRule();
62 | void parseDotDirective();
63 | bool parseCommand(QList& commands, bool inferenceRule);
64 | void parseCommandLine(const QString& cmdLine, QList& commands, bool inferenceRule);
65 | void parseInlineFiles(Command& cmd, bool inferenceRule);
66 | void checkForCycles(DescriptionBlock* target);
67 | void resetCycleChecker(DescriptionBlock* target);
68 | QVector findRulesByTargetName(const QString& targetFilePath);
69 | void preselectInferenceRules(DescriptionBlock *target);
70 | void error(const QString& msg);
71 |
72 | private:
73 | Preprocessor* m_preprocessor;
74 | QString m_line;
75 | bool m_silentCommands;
76 | bool m_ignoreExitCodes;
77 |
78 | QRegExp m_rexDotDirective;
79 | QRegExp m_rexInferenceRule;
80 | QRegExp m_rexSingleWhiteSpace;
81 |
82 | Makefile* m_makefile;
83 | QStringList m_suffixes;
84 | QStringList m_activeTargets;
85 | QHash m_syncPoints;
86 | QHash > m_ruleIdxByToExtension;
87 | };
88 |
89 | } // namespace NMakeFile
90 |
91 | #endif // PARSER_H
92 |
--------------------------------------------------------------------------------
/src/jomlib/ppexpr.g:
--------------------------------------------------------------------------------
1 | ----------------------------------------------------------------------------
2 | --
3 | -- Copyright (C) 2016 The Qt Company Ltd.
4 | -- Contact: https://www.qt.io/licensing/
5 | --
6 | -- This file is part of jom.
7 | --
8 | -- Commercial License Usage
9 | -- Licensees holding valid commercial Qt licenses may use this file in
10 | -- accordance with the commercial license agreement provided with the
11 | -- Software or, alternatively, in accordance with the terms contained in
12 | -- a written agreement between you and The Qt Company. For licensing terms
13 | -- and conditions see https://www.qt.io/terms-conditions. For further
14 | -- information use the contact form at https://www.qt.io/contact-us.
15 | --
16 | -- GNU General Public License Usage
17 | -- Alternatively, this file may be used under the terms of the GNU
18 | -- General Public License version 3 as published by the Free Software
19 | -- Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | -- included in the packaging of this file. Please review the following
21 | -- information to ensure the GNU General Public License requirements will
22 | -- be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | --
24 | ----------------------------------------------------------------------------
25 |
26 | %parser ppexpr_grammar
27 | %decl ppexprparser.h
28 | %impl ppexprparser.cpp
29 |
30 | %token_prefix T_
31 |
32 | %token NUMBER
33 | %token STRING
34 | %token BOOL_AND
35 | %token BOOL_OR
36 | %token BIT_AND
37 | %token BIT_OR
38 | %token EQUAL
39 | %token NOT_EQUAL
40 | %token LESS_THAN
41 | %token GREATER_THAN
42 | %token EQUAL_OR_LESS_THAN
43 | %token EQUAL_OR_GREATER_THAN
44 | %token SHIFT_LEFT
45 | %token SHIFT_RIGHT
46 | %token PLUS
47 | %token MINUS
48 | %token MULT
49 | %token DIV
50 | %token MOD
51 | %token BIT_NOT
52 | %token BOOL_NOT
53 | %token LEFT_PAREN
54 | %token RIGHT_PAREN
55 | %token LINEFEED
56 |
57 | %start expression
58 |
59 | /:
60 | #include "ppexpr_grammar_p.h"
61 | #include
62 |
63 | namespace NMakeFile {
64 | class MacroTable;
65 | }
66 |
67 | class PPExprParser : protected $table
68 | {
69 | public:
70 | PPExprParser();
71 | ~PPExprParser();
72 |
73 | bool parse(const char* str);
74 |
75 | int expressionValue()
76 | {
77 | return sym(1).num;
78 | }
79 |
80 | QByteArray errorMessage() const
81 | {
82 | return m_errorMessage;
83 | }
84 |
85 | void setMacroTable(NMakeFile::MacroTable* macroTable)
86 | {
87 | m_macroTable = macroTable;
88 | }
89 |
90 | protected:
91 | struct Value
92 | {
93 | #ifdef _DEBUG
94 | Value()
95 | : num(0)
96 | {}
97 | #endif
98 |
99 | union {
100 | int num;
101 | QByteArray* str;
102 | };
103 | };
104 |
105 | protected:
106 | int yylex();
107 | inline void reallocateStack();
108 |
109 | inline Value &sym(int index)
110 | { return sym_stack [tos + index - 1]; }
111 |
112 | protected:
113 | void* yyInputBuffer;
114 | Value yylval;
115 | int tos;
116 | int stack_size;
117 | Value *sym_stack;
118 | int *state_stack;
119 | NMakeFile::MacroTable* m_macroTable;
120 | QByteArray m_errorMessage;
121 | };
122 | :/
123 |
124 | /.
125 | #include "ppexprparser.h"
126 | #include "macrotable.h"
127 | #include "ppexpr-lex.inc"
128 |
129 | PPExprParser::PPExprParser()
130 | : stack_size(0),
131 | sym_stack(0),
132 | state_stack(0),
133 | m_macroTable(0)
134 | {
135 | }
136 |
137 | PPExprParser::~PPExprParser()
138 | {
139 | if (stack_size) {
140 | free(sym_stack);
141 | free(state_stack);
142 | }
143 | }
144 |
145 | inline void PPExprParser::reallocateStack()
146 | {
147 | if (!stack_size)
148 | stack_size = 128;
149 | else
150 | stack_size <<= 1;
151 |
152 | sym_stack = reinterpret_cast (realloc(sym_stack, stack_size * sizeof(Value)));
153 | state_stack = reinterpret_cast (realloc(state_stack, stack_size * sizeof(int)));
154 | }
155 |
156 | bool PPExprParser::parse(const char* str)
157 | {
158 | const int INITIAL_STATE = 0;
159 | int yytoken = -1;
160 |
161 | if (!state_stack)
162 | reallocateStack();
163 |
164 | tos = 0;
165 | m_errorMessage.clear();
166 | state_stack[++tos] = INITIAL_STATE;
167 | yyInputBuffer = yy_scan_string(str);
168 | if (!yyInputBuffer) {
169 | m_errorMessage = "Can't create lexer's input buffer.";
170 | return false;
171 | }
172 |
173 | while (true)
174 | {
175 | if (yytoken == -1 && - TERMINAL_COUNT != action_index [state_stack [tos]]) {
176 | yytoken = yylex();
177 | #ifdef DEBUG_GRAMMAR
178 | printf("*** yylex %d\n", yytoken);
179 | #endif
180 | }
181 |
182 | int act = t_action(state_stack [tos], yytoken);
183 |
184 | if (act == ACCEPT_STATE) {
185 | yy_delete_buffer((YY_BUFFER_STATE)yyInputBuffer);
186 | return true;
187 | }
188 |
189 | else if (act > 0) {
190 | if (++tos == stack_size) {
191 | reallocateStack();
192 | if (!state_stack) {
193 | m_errorMessage = "stack overflow";
194 | yy_delete_buffer((YY_BUFFER_STATE)yyInputBuffer);
195 | return false;
196 | }
197 | }
198 |
199 | sym_stack [tos] = yylval;
200 | state_stack [tos] = act;
201 | yytoken = -1;
202 | }
203 |
204 | else if (act < 0)
205 | {
206 | int r = - act - 1;
207 |
208 | #ifdef DEBUG_GRAMMAR
209 | int ridx = rule_index [r];
210 | printf ("*** reduce using rule %d %s ::=", r + 1, spell[rule_info [ridx]]);
211 | ++ridx;
212 | for (int i = ridx; i < ridx + rhs [r]; ++i)
213 | {
214 | int symbol = rule_info [i];
215 | if (const char *name = spell [symbol])
216 | printf (" %s", name);
217 | else
218 | printf (" #%d", symbol);
219 | }
220 | printf ("\n");
221 | #endif
222 |
223 | tos -= rhs [r];
224 | act = state_stack [tos++];
225 |
226 | switch (r) {
227 | ./
228 |
229 | expression ::= term0;
230 | term0 ::= term1;
231 | term0 ::= term0 BOOL_AND term1;
232 | /.
233 | case $rule_number: // $rule
234 | sym(1).num = (sym(1).num != 0 && sym(3).num != 0) ? 1 : 0;
235 | break;
236 | ./
237 |
238 | term0 ::= term0 BOOL_OR term1;
239 | /.
240 | case $rule_number: // $rule
241 | sym(1).num = (sym(1).num != 0 || sym(3).num != 0) ? 1 : 0;
242 | break;
243 | ./
244 |
245 | term0 ::= term0 BIT_AND term1;
246 | /.
247 | case $rule_number: // $rule
248 | sym(1).num &= sym(3).num;
249 | break;
250 | ./
251 |
252 | term0 ::= term0 BIT_OR term1;
253 | /.
254 | case $rule_number: // $rule
255 | sym(1).num |= sym(3).num;
256 | break;
257 | ./
258 |
259 | term1 ::= term2;
260 | term1 ::= strterm1;
261 |
262 | strterm1 ::= STRING EQUAL STRING;
263 | /.
264 | case $rule_number: { // $rule
265 | QByteArray* lhs = sym(1).str;
266 | QByteArray* rhs = sym(3).str;
267 | sym(1).num = (*lhs == *rhs) ? 1 : 0;
268 | delete lhs;
269 | delete rhs;
270 | break;
271 | }
272 | ./
273 |
274 | strterm1 ::= STRING NOT_EQUAL STRING;
275 | /.
276 | case $rule_number: { // $rule
277 | QByteArray* lhs = sym(1).str;
278 | QByteArray* rhs = sym(3).str;
279 | sym(1).num = (*lhs == *rhs) ? 0 : 1;
280 | delete lhs;
281 | delete rhs;
282 | break;
283 | }
284 | ./
285 |
286 | term2 ::= term3;
287 | term2 ::= term2 EQUAL term3;
288 | /.
289 | case $rule_number: // $rule
290 | sym(1).num = (sym(1).num == sym(3).num);
291 | break;
292 | ./
293 |
294 | term2 ::= term2 NOT_EQUAL term3;
295 | /.
296 | case $rule_number: // $rule
297 | sym(1).num = (sym(1).num != sym(3).num);
298 | break;
299 | ./
300 |
301 | term2 ::= term2 LESS_THAN term3;
302 | /.
303 | case $rule_number: // $rule
304 | sym(1).num = (sym(1).num < sym(3).num);
305 | break;
306 | ./
307 |
308 | term2 ::= term2 GREATER_THAN term3;
309 | /.
310 | case $rule_number: // $rule
311 | sym(1).num = (sym(1).num > sym(3).num);
312 | break;
313 | ./
314 |
315 | term2 ::= term2 EQUAL_OR_LESS_THAN term3;
316 | /.
317 | case $rule_number: // $rule
318 | sym(1).num = (sym(1).num <= sym(3).num);
319 | break;
320 | ./
321 |
322 | term2 ::= term2 EQUAL_OR_GREATER_THAN term3;
323 | /.
324 | case $rule_number: // $rule
325 | sym(1).num = (sym(1).num >= sym(3).num);
326 | break;
327 | ./
328 |
329 | term3 ::= term4;
330 | term3 ::= term3 SHIFT_LEFT term4;
331 | /.
332 | case $rule_number: // $rule
333 | sym(1).num <<= sym(3).num;
334 | break;
335 | ./
336 |
337 | term3 ::= term3 SHIFT_RIGHT term4;
338 | /.
339 | case $rule_number: // $rule
340 | sym(1).num >>= sym(3).num;
341 | break;
342 | ./
343 |
344 | term4 ::= term5;
345 | term4 ::= term4 PLUS term5;
346 | /.
347 | case $rule_number: // $rule
348 | sym(1).num += sym(3).num;
349 | break;
350 | ./
351 |
352 | term4 ::= term4 MINUS term5;
353 | /.
354 | case $rule_number: // $rule
355 | sym(1).num -= sym(3).num;
356 | break;
357 | ./
358 |
359 | term5 ::= term6;
360 | term5 ::= term5 MULT term6;
361 | /.
362 | case $rule_number: // $rule
363 | sym(1).num *= sym(3).num;
364 | break;
365 | ./
366 |
367 | term5 ::= term5 DIV term6;
368 | /.
369 | case $rule_number: { // $rule
370 | const int rhs = sym(3).num;
371 | if (rhs == 0) {
372 | m_errorMessage = "division by zero";
373 | yy_delete_buffer((YY_BUFFER_STATE)yyInputBuffer);
374 | return false;
375 | }
376 | sym(1).num /= rhs;
377 | break;
378 | }
379 | ./
380 |
381 | term5 ::= term5 MOD term6;
382 | /.
383 | case $rule_number: // $rule
384 | sym(1).num %= sym(3).num;
385 | break;
386 | ./
387 |
388 | term6 ::= primary;
389 | term6 ::= MINUS primary;
390 | /.
391 | case $rule_number: // $rule
392 | sym(1).num = -sym(2).num;
393 | break;
394 | ./
395 |
396 | term6 ::= BIT_NOT primary;
397 | /.
398 | case $rule_number: // $rule
399 | sym(1).num = ~sym(2).num;
400 | break;
401 | ./
402 |
403 | term6 ::= BOOL_NOT primary;
404 | /.
405 | case $rule_number: // $rule
406 | sym(1).num = (sym(2).num == 0) ? 1 : 0;
407 | break;
408 | ./
409 |
410 | primary ::= NUMBER;
411 | primary ::= LEFT_PAREN term0 RIGHT_PAREN;
412 | /.
413 | case $rule_number: // $rule
414 | sym(1).num = sym(2).num;
415 | break;
416 | ./
417 |
418 | /.
419 | } // switch
420 |
421 | state_stack [tos] = nt_action (act, lhs [r] - TERMINAL_COUNT);
422 | }
423 | else
424 | {
425 | // ### ERROR RECOVERY HERE
426 | break;
427 | }
428 | }
429 |
430 | m_errorMessage = "Syntax Error";
431 | yy_delete_buffer((YY_BUFFER_STATE)yyInputBuffer);
432 | return false;
433 | }
434 | ./
435 |
436 |
--------------------------------------------------------------------------------
/src/jomlib/ppexpr.l:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | %option 8bit nounistd batch
27 | %option warn
28 | /*%option nodefault*/
29 | %option outfile="ppexpr-lex.inc"
30 | /*%option header-file="ppexpr-lex.h"*/
31 |
32 | %{
33 | #define YY_DECL int PPExprParser::yylex()
34 | #define ECHO
35 | #define YY_SKIP_YYWRAP
36 | #define fileno _fileno
37 |
38 | static int isatty (int)
39 | {
40 | return 0;
41 | }
42 |
43 | static int yywrap()
44 | {
45 | return 1;
46 | }
47 | %}
48 |
49 | %x STATE_STRING
50 | %x STATE_DEFINED
51 | %x STATE_EXIST
52 | %x STATE_SHELLCOMMAND
53 |
54 | %%
55 |
56 | [ \t]+ /* eat whitespace */
57 | [0-9]+ {
58 | yylval.num = atoi(yytext);
59 | return T_NUMBER;
60 | }
61 | \r?\n return T_LINEFEED;
62 | "&&" return T_BOOL_AND;
63 | "||" return T_BOOL_OR;
64 | "&" return T_BIT_AND;
65 | "|" return T_BIT_OR;
66 | "!=" return T_NOT_EQUAL;
67 | "==" return T_EQUAL;
68 | "<" return T_LESS_THAN;
69 | ">" return T_GREATER_THAN;
70 | "<=" return T_EQUAL_OR_LESS_THAN;
71 | ">=" return T_EQUAL_OR_GREATER_THAN;
72 | "<<" return T_SHIFT_LEFT;
73 | ">>" return T_SHIFT_RIGHT;
74 | "+" return T_PLUS;
75 | "-" return T_MINUS;
76 | "*" return T_MULT;
77 | "/" return T_DIV;
78 | "%" return T_MOD;
79 | "~" return T_BIT_NOT;
80 | "!" return T_BOOL_NOT;
81 | "(" return T_LEFT_PAREN;
82 | ")" return T_RIGHT_PAREN;
83 |
84 | \" {
85 | BEGIN(STATE_STRING);
86 | yylval.str = new QByteArray();
87 | }
88 |
89 | "[" {
90 | BEGIN(STATE_SHELLCOMMAND);
91 | yylval.str = new QByteArray();
92 | }
93 |
94 | (?i:DEFINED) BEGIN(STATE_DEFINED);
95 | (?i:EXIST) BEGIN(STATE_EXIST);
96 |
97 | {
98 | [:blank:]+ /* eat whitespace */
99 | "("[^\)]+")" {
100 | BEGIN(INITIAL);
101 | QByteArray macroName(yytext);
102 | int idx = macroName.indexOf('(');
103 | macroName.remove(0, idx + 1);
104 | idx = macroName.lastIndexOf(')');
105 | macroName.truncate(idx);
106 | macroName = macroName.trimmed();
107 | if (macroName.startsWith('\"'))
108 | macroName.remove(0, 1);
109 | if (macroName.endsWith('\"'))
110 | macroName.chop(1);
111 | yylval.num = m_macroTable->isMacroDefined(QString::fromLatin1(macroName.constData())) ? 1 : 0;
112 | return T_NUMBER;
113 | }
114 | }
115 |
116 | {
117 | [:blank:]+ /* eat whitespace */
118 | "(".+")" {
119 | BEGIN(INITIAL);
120 | QByteArray fileName(yytext);
121 | int idx = fileName.indexOf('(');
122 | fileName.remove(0, idx + 1);
123 | idx = fileName.lastIndexOf(')');
124 | fileName.truncate(idx);
125 | fileName = fileName.trimmed();
126 | if (fileName.startsWith('\"'))
127 | fileName.remove(0, 1);
128 | if (fileName.endsWith('\"'))
129 | fileName.chop(1);
130 | yylval.num = QFile::exists(QString::fromLatin1(fileName.constData())) ? 1 : 0;
131 | return T_NUMBER;
132 | }
133 | }
134 |
135 | "EXIST"[:blank:]*"(".*")" {
136 | QByteArray fileName(yytext);
137 | int idx = fileName.indexOf('(');
138 | fileName.remove(0, idx + 1);
139 | idx = fileName.lastIndexOf(')');
140 | fileName.truncate(idx);
141 | fileName = fileName.trimmed();
142 | if (fileName.startsWith('\"'))
143 | fileName.remove(0, 1);
144 | if (fileName.endsWith('\"'))
145 | fileName.chop(1);
146 | yylval.num = QFile::exists(QString::fromLatin1(fileName.constData())) ? 1 : 0;
147 | return T_NUMBER;
148 | }
149 |
150 | {
151 | [^\n\"]+ yylval.str->append(yytext, static_cast(yyleng));
152 | \"\" yylval.str->append('\"');
153 | \" {
154 | BEGIN(INITIAL);
155 | return T_STRING;
156 | }
157 | }
158 |
159 | {
160 | [^\n\x5b\x5d\x5e]+ yylval.str->append(yytext, static_cast(yyleng));
161 | "^[" yylval.str->append('[');
162 | "^]" yylval.str->append(']');
163 | "]" {
164 | BEGIN(INITIAL);
165 | int exitCode = system(yylval.str->data());
166 | delete yylval.str;
167 | yylval.num = exitCode;
168 | return T_NUMBER;
169 | }
170 | }
171 |
172 | %%
173 |
174 |
--------------------------------------------------------------------------------
/src/jomlib/ppexpr_grammar.cpp:
--------------------------------------------------------------------------------
1 | // This file was generated by qlalr - DO NOT EDIT!
2 | #include "ppexpr_grammar_p.h"
3 |
4 | const char *const ppexpr_grammar::spell [] = {
5 | "end of file", 0, 0, 0, 0, 0, 0, 0, 0, 0,
6 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7 | 0, 0, 0, 0, 0,
8 | #ifndef QLALR_NO_PPEXPR_GRAMMAR_DEBUG_INFO
9 | "expression", "term0", "term1", "term2", "strterm1",
10 | "term3", "term4", "term5", "term6", "primary", "$accept"
11 | #endif // QLALR_NO_PPEXPR_GRAMMAR_DEBUG_INFO
12 | };
13 |
14 | const short ppexpr_grammar::lhs [] = {
15 | 25, 26, 26, 26, 26, 26, 27, 27, 29, 29,
16 | 28, 28, 28, 28, 28, 28, 28, 30, 30, 30,
17 | 31, 31, 31, 32, 32, 32, 32, 33, 33, 33,
18 | 33, 34, 34, 35};
19 |
20 | const short ppexpr_grammar::rhs [] = {
21 | 1, 1, 3, 3, 3, 3, 1, 1, 3, 3,
22 | 1, 3, 3, 3, 3, 3, 3, 1, 3, 3,
23 | 1, 3, 3, 1, 3, 3, 3, 1, 2, 2,
24 | 2, 1, 3, 2};
25 |
26 |
27 | #ifndef QLALR_NO_PPEXPR_GRAMMAR_DEBUG_INFO
28 | const int ppexpr_grammar::rule_info [] = {
29 | 25, 26
30 | , 26, 27
31 | , 26, 26, 3, 27
32 | , 26, 26, 4, 27
33 | , 26, 26, 5, 27
34 | , 26, 26, 6, 27
35 | , 27, 28
36 | , 27, 29
37 | , 29, 2, 7, 2
38 | , 29, 2, 8, 2
39 | , 28, 30
40 | , 28, 28, 7, 30
41 | , 28, 28, 8, 30
42 | , 28, 28, 9, 30
43 | , 28, 28, 10, 30
44 | , 28, 28, 11, 30
45 | , 28, 28, 12, 30
46 | , 30, 31
47 | , 30, 30, 13, 31
48 | , 30, 30, 14, 31
49 | , 31, 32
50 | , 31, 31, 15, 32
51 | , 31, 31, 16, 32
52 | , 32, 33
53 | , 32, 32, 17, 33
54 | , 32, 32, 18, 33
55 | , 32, 32, 19, 33
56 | , 33, 34
57 | , 33, 16, 34
58 | , 33, 20, 34
59 | , 33, 21, 34
60 | , 34, 1
61 | , 34, 22, 26, 23
62 | , 35, 25, 0};
63 |
64 | const int ppexpr_grammar::rule_index [] = {
65 | 0, 2, 4, 8, 12, 16, 20, 22, 24, 28,
66 | 32, 34, 38, 42, 46, 50, 54, 58, 60, 64,
67 | 68, 70, 74, 78, 80, 84, 88, 92, 94, 97,
68 | 100, 103, 105, 109};
69 | #endif // QLALR_NO_PPEXPR_GRAMMAR_DEBUG_INFO
70 |
71 | const short ppexpr_grammar::action_default [] = {
72 | 0, 0, 0, 0, 0, 32, 0, 0, 28, 8,
73 | 1, 2, 7, 11, 18, 21, 24, 30, 31, 0,
74 | 0, 0, 0, 0, 33, 5, 6, 3, 4, 29,
75 | 0, 0, 9, 10, 34, 0, 0, 0, 0, 0,
76 | 0, 12, 0, 0, 19, 0, 0, 23, 0, 0,
77 | 0, 26, 27, 25, 22, 20, 17, 16, 15, 14,
78 | 13};
79 |
80 | const short ppexpr_grammar::goto_default [] = {
81 | 7, 10, 11, 12, 9, 13, 14, 15, 16, 8,
82 | 0};
83 |
84 | const short ppexpr_grammar::action_index [] = {
85 | 117, 1, 2, 76, 5, -25, 3, 0, -25, -25,
86 | 45, -25, 113, 6, -8, 18, -25, -25, -25, 57,
87 | 110, 117, 85, 141, -25, -25, -25, -25, -25, -25,
88 | 23, -1, -25, -25, -25, 51, 93, 69, 25, 37,
89 | 69, 15, 69, 69, -3, 69, 93, 18, 69, 69,
90 | 69, -25, -25, -25, 18, 16, 20, 20, -9, 4,
91 | 8,
92 |
93 | -11, -9, -7, 3, -8, -11, -11, -11, -11, -11,
94 | -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
95 | 1, 12, 4, 21, -11, -11, -11, -11, -11, -11,
96 | -11, -11, -11, -11, -11, 10, 15, 16, 0, 6,
97 | 7, -11, 11, 13, -11, 9, 17, -11, -1, 2,
98 | 5, -11, -11, -11, -11, -11, -11, -11, -11, -11,
99 | -11};
100 |
101 | const short ppexpr_grammar::action_info [] = {
102 | 34, 33, 5, 5, 42, 43, 5, 46, 45, 0,
103 | 30, 31, 46, 45, 0, 0, 0, 42, 43, 42,
104 | 43, 42, 43, 3, 3, 32, 5, 3, 42, 43,
105 | 0, 46, 45, 42, 43, 50, 48, 49, 5, 0,
106 | 0, 4, 0, 0, 0, 1, 2, 3, 22, 23,
107 | 20, 21, 5, 4, 0, 0, 0, 1, 2, 3,
108 | 22, 23, 20, 21, 0, 0, 0, 4, 0, 0,
109 | 5, 1, 2, 3, 0, 0, 0, 5, 6, 0,
110 | 24, 0, 0, 0, 0, 4, 5, 6, 0, 1,
111 | 2, 3, 4, 0, 5, 0, 1, 2, 3, 0,
112 | 0, 4, 0, 0, 0, 1, 2, 3, 0, 4,
113 | 0, 5, 6, 1, 2, 3, 0, 0, 5, 6,
114 | 35, 40, 39, 38, 37, 36, 4, 0, 0, 0,
115 | 1, 2, 3, 4, 0, 0, 0, 1, 2, 3,
116 | 0, 0, 5, 6, 0, 0, 0, 0, 0, 0,
117 | 0, 0, 0, 0, 0, 0, 0, 4, 0, 0,
118 | 0, 1, 2, 3, 0, 0,
119 |
120 | 17, 29, 18, 25, 19, 58, 27, 51, 0, 0,
121 | 52, 59, 60, 53, 26, 41, 47, 44, 0, 55,
122 | 56, 57, 0, 28, 54, 0, 0, 0, 0, 0,
123 | 0, 0};
124 |
125 | const short ppexpr_grammar::action_check [] = {
126 | 0, 2, 1, 1, 13, 14, 1, 15, 16, -1,
127 | 7, 8, 15, 16, -1, -1, -1, 13, 14, 13,
128 | 14, 13, 14, 22, 22, 2, 1, 22, 13, 14,
129 | -1, 15, 16, 13, 14, 17, 18, 19, 1, -1,
130 | -1, 16, -1, -1, -1, 20, 21, 22, 3, 4,
131 | 5, 6, 1, 16, -1, -1, -1, 20, 21, 22,
132 | 3, 4, 5, 6, -1, -1, -1, 16, -1, -1,
133 | 1, 20, 21, 22, -1, -1, -1, 1, 2, -1,
134 | 23, -1, -1, -1, -1, 16, 1, 2, -1, 20,
135 | 21, 22, 16, -1, 1, -1, 20, 21, 22, -1,
136 | -1, 16, -1, -1, -1, 20, 21, 22, -1, 16,
137 | -1, 1, 2, 20, 21, 22, -1, -1, 1, 2,
138 | 7, 8, 9, 10, 11, 12, 16, -1, -1, -1,
139 | 20, 21, 22, 16, -1, -1, -1, 20, 21, 22,
140 | -1, -1, 1, 2, -1, -1, -1, -1, -1, -1,
141 | -1, -1, -1, -1, -1, -1, -1, 16, -1, -1,
142 | -1, 20, 21, 22, -1, -1,
143 |
144 | 9, 9, 9, 2, 1, 5, 2, 8, -1, -1,
145 | 8, 5, 5, 8, 2, 5, 7, 6, -1, 6,
146 | 5, 5, -1, 2, 7, -1, -1, -1, -1, -1,
147 | -1, -1};
148 |
149 |
--------------------------------------------------------------------------------
/src/jomlib/ppexpr_grammar_p.h:
--------------------------------------------------------------------------------
1 | // This file was generated by qlalr - DO NOT EDIT!
2 | #ifndef PPEXPR_GRAMMAR_P_H
3 | #define PPEXPR_GRAMMAR_P_H
4 |
5 | class ppexpr_grammar
6 | {
7 | public:
8 | enum VariousConstants {
9 | EOF_SYMBOL = 0,
10 | T_BIT_AND = 5,
11 | T_BIT_NOT = 20,
12 | T_BIT_OR = 6,
13 | T_BOOL_AND = 3,
14 | T_BOOL_NOT = 21,
15 | T_BOOL_OR = 4,
16 | T_DIV = 18,
17 | T_EQUAL = 7,
18 | T_EQUAL_OR_GREATER_THAN = 12,
19 | T_EQUAL_OR_LESS_THAN = 11,
20 | T_GREATER_THAN = 10,
21 | T_LEFT_PAREN = 22,
22 | T_LESS_THAN = 9,
23 | T_LINEFEED = 24,
24 | T_MINUS = 16,
25 | T_MOD = 19,
26 | T_MULT = 17,
27 | T_NOT_EQUAL = 8,
28 | T_NUMBER = 1,
29 | T_PLUS = 15,
30 | T_RIGHT_PAREN = 23,
31 | T_SHIFT_LEFT = 13,
32 | T_SHIFT_RIGHT = 14,
33 | T_STRING = 2,
34 |
35 | ACCEPT_STATE = 34,
36 | RULE_COUNT = 34,
37 | STATE_COUNT = 61,
38 | TERMINAL_COUNT = 25,
39 | NON_TERMINAL_COUNT = 11,
40 |
41 | GOTO_INDEX_OFFSET = 61,
42 | GOTO_INFO_OFFSET = 166,
43 | GOTO_CHECK_OFFSET = 166
44 | };
45 |
46 | static const char *const spell [];
47 | static const short lhs [];
48 | static const short rhs [];
49 |
50 | #ifndef QLALR_NO_PPEXPR_GRAMMAR_DEBUG_INFO
51 | static const int rule_index [];
52 | static const int rule_info [];
53 | #endif // QLALR_NO_PPEXPR_GRAMMAR_DEBUG_INFO
54 |
55 | static const short goto_default [];
56 | static const short action_default [];
57 | static const short action_index [];
58 | static const short action_info [];
59 | static const short action_check [];
60 |
61 | static inline int nt_action (int state, int nt)
62 | {
63 | const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt;
64 | if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt)
65 | return goto_default [nt];
66 |
67 | return action_info [GOTO_INFO_OFFSET + yyn];
68 | }
69 |
70 | static inline int t_action (int state, int token)
71 | {
72 | const int yyn = action_index [state] + token;
73 |
74 | if (yyn < 0 || action_check [yyn] != token)
75 | return - action_default [state];
76 |
77 | return action_info [yyn];
78 | }
79 | };
80 |
81 |
82 | #endif // PPEXPR_GRAMMAR_P_H
83 |
84 |
--------------------------------------------------------------------------------
/src/jomlib/ppexprparser.cpp:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #include "ppexprparser.h"
27 | #include "macrotable.h"
28 | #include "ppexpr-lex.inc"
29 |
30 | PPExprParser::PPExprParser()
31 | : stack_size(0),
32 | sym_stack(0),
33 | state_stack(0),
34 | m_macroTable(0)
35 | {
36 | }
37 |
38 | PPExprParser::~PPExprParser()
39 | {
40 | if (stack_size) {
41 | free(sym_stack);
42 | free(state_stack);
43 | }
44 | }
45 |
46 | inline void PPExprParser::reallocateStack()
47 | {
48 | if (!stack_size)
49 | stack_size = 128;
50 | else
51 | stack_size <<= 1;
52 |
53 | sym_stack = reinterpret_cast (realloc(sym_stack, stack_size * sizeof(Value)));
54 | state_stack = reinterpret_cast (realloc(state_stack, stack_size * sizeof(int)));
55 | }
56 |
57 | bool PPExprParser::parse(const char* str)
58 | {
59 | const int INITIAL_STATE = 0;
60 | int yytoken = -1;
61 |
62 | if (!state_stack)
63 | reallocateStack();
64 |
65 | tos = 0;
66 | m_errorMessage.clear();
67 | state_stack[++tos] = INITIAL_STATE;
68 | yyInputBuffer = yy_scan_string(str);
69 | if (!yyInputBuffer) {
70 | m_errorMessage = "Can't create lexer's input buffer.";
71 | return false;
72 | }
73 |
74 | while (true)
75 | {
76 | if (yytoken == -1 && - TERMINAL_COUNT != action_index [state_stack [tos]]) {
77 | yytoken = yylex();
78 | #ifdef DEBUG_GRAMMAR
79 | printf("*** yylex %d\n", yytoken);
80 | #endif
81 | }
82 |
83 | int act = t_action(state_stack [tos], yytoken);
84 |
85 | if (act == ACCEPT_STATE) {
86 | yy_delete_buffer((YY_BUFFER_STATE)yyInputBuffer);
87 | return true;
88 | }
89 |
90 | else if (act > 0) {
91 | if (++tos == stack_size) {
92 | reallocateStack();
93 | if (!state_stack) {
94 | m_errorMessage = "stack overflow";
95 | yy_delete_buffer((YY_BUFFER_STATE)yyInputBuffer);
96 | return false;
97 | }
98 | }
99 |
100 | sym_stack [tos] = yylval;
101 | state_stack [tos] = act;
102 | yytoken = -1;
103 | }
104 |
105 | else if (act < 0)
106 | {
107 | int r = - act - 1;
108 |
109 | #ifdef DEBUG_GRAMMAR
110 | int ridx = rule_index [r];
111 | printf ("*** reduce using rule %d %s ::=", r + 1, spell[rule_info [ridx]]);
112 | ++ridx;
113 | for (int i = ridx; i < ridx + rhs [r]; ++i)
114 | {
115 | int symbol = rule_info [i];
116 | if (const char *name = spell [symbol])
117 | printf (" %s", name);
118 | else
119 | printf (" #%d", symbol);
120 | }
121 | printf ("\n");
122 | #endif
123 |
124 | tos -= rhs [r];
125 | act = state_stack [tos++];
126 |
127 | switch (r) {
128 |
129 | case 2: // term0
130 | sym(1).num = (sym(1).num != 0 && sym(3).num != 0) ? 1 : 0;
131 | break;
132 |
133 | case 3: // term0
134 | sym(1).num = (sym(1).num != 0 || sym(3).num != 0) ? 1 : 0;
135 | break;
136 |
137 | case 4: // term0
138 | sym(1).num &= sym(3).num;
139 | break;
140 |
141 | case 5: // term0
142 | sym(1).num |= sym(3).num;
143 | break;
144 |
145 | case 8: { // strterm1
146 | QByteArray* lhs = sym(1).str;
147 | QByteArray* rhs = sym(3).str;
148 | sym(1).num = (*lhs == *rhs) ? 1 : 0;
149 | delete lhs;
150 | delete rhs;
151 | break;
152 | }
153 |
154 | case 9: { // strterm1
155 | QByteArray* lhs = sym(1).str;
156 | QByteArray* rhs = sym(3).str;
157 | sym(1).num = (*lhs == *rhs) ? 0 : 1;
158 | delete lhs;
159 | delete rhs;
160 | break;
161 | }
162 |
163 | case 11: // term2
164 | sym(1).num = (sym(1).num == sym(3).num);
165 | break;
166 |
167 | case 12: // term2
168 | sym(1).num = (sym(1).num != sym(3).num);
169 | break;
170 |
171 | case 13: // term2
172 | sym(1).num = (sym(1).num < sym(3).num);
173 | break;
174 |
175 | case 14: // term2
176 | sym(1).num = (sym(1).num > sym(3).num);
177 | break;
178 |
179 | case 15: // term2
180 | sym(1).num = (sym(1).num <= sym(3).num);
181 | break;
182 |
183 | case 16: // term2
184 | sym(1).num = (sym(1).num >= sym(3).num);
185 | break;
186 |
187 | case 18: // term3
188 | sym(1).num <<= sym(3).num;
189 | break;
190 |
191 | case 19: // term3
192 | sym(1).num >>= sym(3).num;
193 | break;
194 |
195 | case 21: // term4
196 | sym(1).num += sym(3).num;
197 | break;
198 |
199 | case 22: // term4
200 | sym(1).num -= sym(3).num;
201 | break;
202 |
203 | case 24: // term5
204 | sym(1).num *= sym(3).num;
205 | break;
206 |
207 | case 25: { // term5
208 | const int rhs = sym(3).num;
209 | if (rhs == 0) {
210 | m_errorMessage = "division by zero";
211 | yy_delete_buffer((YY_BUFFER_STATE)yyInputBuffer);
212 | return false;
213 | }
214 | sym(1).num /= rhs;
215 | break;
216 | }
217 |
218 | case 26: // term5
219 | sym(1).num %= sym(3).num;
220 | break;
221 |
222 | case 28: // term6
223 | sym(1).num = -sym(2).num;
224 | break;
225 |
226 | case 29: // term6
227 | sym(1).num = ~sym(2).num;
228 | break;
229 |
230 | case 30: // term6
231 | sym(1).num = (sym(2).num == 0) ? 1 : 0;
232 | break;
233 |
234 | case 32: // primary
235 | sym(1).num = sym(2).num;
236 | break;
237 |
238 | } // switch
239 |
240 | state_stack [tos] = nt_action (act, lhs [r] - TERMINAL_COUNT);
241 | }
242 | else
243 | {
244 | // ### ERROR RECOVERY HERE
245 | break;
246 | }
247 | }
248 |
249 | m_errorMessage = "Syntax Error";
250 | yy_delete_buffer((YY_BUFFER_STATE)yyInputBuffer);
251 | return false;
252 | }
253 |
--------------------------------------------------------------------------------
/src/jomlib/ppexprparser.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #include "ppexpr_grammar_p.h"
27 | #include
28 |
29 | namespace NMakeFile {
30 | class MacroTable;
31 | }
32 |
33 | class PPExprParser : protected ppexpr_grammar
34 | {
35 | public:
36 | PPExprParser();
37 | ~PPExprParser();
38 |
39 | bool parse(const char* str);
40 |
41 | int expressionValue()
42 | {
43 | return sym(1).num;
44 | }
45 |
46 | QByteArray errorMessage() const
47 | {
48 | return m_errorMessage;
49 | }
50 |
51 | void setMacroTable(NMakeFile::MacroTable* macroTable)
52 | {
53 | m_macroTable = macroTable;
54 | }
55 |
56 | protected:
57 | struct Value
58 | {
59 | #ifdef _DEBUG
60 | Value()
61 | : num(0)
62 | {}
63 | #endif
64 |
65 | union {
66 | int num;
67 | QByteArray* str;
68 | };
69 | };
70 |
71 | protected:
72 | int yylex();
73 | inline void reallocateStack();
74 |
75 | inline Value &sym(int index)
76 | { return sym_stack [tos + index - 1]; }
77 |
78 | protected:
79 | void* yyInputBuffer;
80 | Value yylval;
81 | int tos;
82 | int stack_size;
83 | Value *sym_stack;
84 | int *state_stack;
85 | NMakeFile::MacroTable* m_macroTable;
86 | QByteArray m_errorMessage;
87 | };
88 |
--------------------------------------------------------------------------------
/src/jomlib/preprocessor.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef PREPROCESSOR_H
27 | #define PREPROCESSOR_H
28 |
29 | #include "makefilelinereader.h"
30 |
31 | #include
32 | #include
33 | #include
34 |
35 | class PPExprParser;
36 |
37 | namespace NMakeFile {
38 |
39 | class MacroTable;
40 | class MakefileLineReader;
41 |
42 | class Preprocessor
43 | {
44 | public:
45 | Preprocessor();
46 | ~Preprocessor();
47 |
48 | void setMacroTable(MacroTable* macroTable);
49 | MacroTable* macroTable() { return m_macroTable; }
50 | bool openFile(const QString& filename);
51 | QString readLine();
52 | uint lineNumber() const;
53 | QString currentFileName() const;
54 | int evaluateExpression(const QString& expr);
55 | bool isInlineFileMode() const { return m_bInlineFileMode; }
56 | void setInlineFileModeEnabled(bool enabled) { m_bInlineFileMode = enabled; }
57 |
58 | static void removeInlineComments(QString& line);
59 |
60 | private:
61 | bool internalOpenFile(QString fileName);
62 | MakefileLine basicReadLine();
63 | typedef void (*JoinFunc)(MakefileLine &, const MakefileLine &);
64 | static void joinLines(MakefileLine &line, const MakefileLine &next);
65 | static void joinPreprocessingDirectiveLines(MakefileLine &line, const MakefileLine &next);
66 | void completeLineImpl(MakefileLine &line, JoinFunc joinFunc);
67 | void completeLine(MakefileLine &line);
68 | void completePreprocessingDirectiveLine(MakefileLine &line);
69 | bool parseMacro(const QString& line);
70 | bool parsePreprocessingDirective(const QString& line);
71 | QString findIncludeFile(const QString &filePathToInclude);
72 | bool isPreprocessingDirective(const QString& line, QString& directive, QString& value);
73 | void skipUntilNextMatchingConditional();
74 | void error(const QString& msg);
75 | void enterConditional(bool followElseBranch);
76 | void exitConditional();
77 | int conditionalDepth() { return m_conditionalStack.count(); }
78 |
79 | private:
80 | struct TextFile
81 | {
82 | MakefileLineReader* reader;
83 | QString fileDirectory;
84 |
85 | TextFile()
86 | : reader(0)
87 | {}
88 |
89 | TextFile(const TextFile& rhs)
90 | : reader(rhs.reader), fileDirectory(rhs.fileDirectory)
91 | {}
92 |
93 | TextFile& operator=(const TextFile& rhs)
94 | {
95 | reader = rhs.reader;
96 | fileDirectory = rhs.fileDirectory;
97 | return *this;
98 | }
99 | };
100 |
101 | QStack m_fileStack;
102 | MacroTable* m_macroTable;
103 | QRegExp m_rexPreprocessingDirective;
104 | QStack m_conditionalStack;
105 | PPExprParser* m_expressionParser;
106 | QStringList m_linesPutBack;
107 | bool m_bInlineFileMode;
108 | };
109 |
110 | } //namespace NMakeFile
111 |
112 | #endif // PREPROCESSOR_H
113 |
--------------------------------------------------------------------------------
/src/jomlib/processenvironment.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef PROCESSENVIRONMENT_H
27 | #define PROCESSENVIRONMENT_H
28 |
29 | #include
30 | #include
31 |
32 | namespace NMakeFile {
33 |
34 | /**
35 | * Key for the ProcessEnvironment class.
36 | */
37 | class ProcessEnvironmentKey
38 | {
39 | public:
40 | ProcessEnvironmentKey(const QString &key)
41 | : m_key(key)
42 | {
43 | }
44 |
45 | ProcessEnvironmentKey(const QLatin1String &key)
46 | : m_key(key)
47 | {
48 | }
49 |
50 | const QString &toQString() const
51 | {
52 | return m_key;
53 | }
54 |
55 | int compare(const ProcessEnvironmentKey &other) const
56 | {
57 | return m_key.compare(other.m_key, Qt::CaseInsensitive);
58 | }
59 |
60 | private:
61 | QString m_key;
62 | };
63 |
64 | inline bool operator < (const ProcessEnvironmentKey &lhs, const ProcessEnvironmentKey &rhs)
65 | {
66 | return lhs.compare(rhs) < 0;
67 | }
68 |
69 | typedef QMap ProcessEnvironment;
70 |
71 | } // namespace NMakeFile
72 |
73 | #endif // PROCESSENVIRONMENT_H
74 |
--------------------------------------------------------------------------------
/src/jomlib/stable.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #define _CRT_RAND_S
27 | #include
28 |
29 | #include
30 |
--------------------------------------------------------------------------------
/src/jomlib/targetexecutor.cpp:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #include "targetexecutor.h"
27 | #include "commandexecutor.h"
28 | #include "dependencygraph.h"
29 | #include "jobclient.h"
30 | #include "options.h"
31 | #include "exception.h"
32 |
33 | #include
34 | #include
35 | #include
36 |
37 | namespace NMakeFile {
38 |
39 | TargetExecutor::TargetExecutor(const ProcessEnvironment &environment)
40 | : m_environment(environment)
41 | , m_jobClient(0)
42 | , m_bAborted(false)
43 | , m_allCommandsSuccessfullyExecuted(true)
44 | {
45 | m_makefile = 0;
46 | m_depgraph = new DependencyGraph();
47 |
48 | for (int i = 0; i < g_options.maxNumberOfJobs; ++i) {
49 | CommandExecutor* executor = new CommandExecutor(this, environment);
50 | connect(executor, SIGNAL(finished(CommandExecutor*, bool)),
51 | this, SLOT(onChildFinished(CommandExecutor*, bool)));
52 |
53 | foreach (CommandExecutor *other, m_processes) {
54 | connect(executor, SIGNAL(environmentChanged(const ProcessEnvironment &)),
55 | other, SLOT(setEnvironment(const ProcessEnvironment &)));
56 | connect(other, SIGNAL(environmentChanged(const ProcessEnvironment &)),
57 | executor, SLOT(setEnvironment(const ProcessEnvironment &)));
58 | }
59 | m_processes.append(executor);
60 | }
61 | m_availableProcesses = m_processes;
62 | m_availableProcesses.first()->setBufferedOutput(false);
63 | }
64 |
65 | TargetExecutor::~TargetExecutor()
66 | {
67 | delete m_depgraph;
68 | }
69 |
70 | void TargetExecutor::apply(Makefile* mkfile, const QStringList& targets)
71 | {
72 | m_bAborted = false;
73 | m_allCommandsSuccessfullyExecuted = true;
74 | m_makefile = mkfile;
75 | m_jobAcquisitionCount = 0;
76 | m_nextTarget = 0;
77 |
78 | if (!m_jobClient) {
79 | m_jobClient = new JobClient(&m_environment, this);
80 | if (!m_jobClient->start()) {
81 | const QString msg = QLatin1String("Can't connect to job server: %1");
82 | throw Exception(msg.arg(m_jobClient->errorString()));
83 | }
84 | connect(m_jobClient, &JobClient::acquired, this, &TargetExecutor::buildNextTarget);
85 | }
86 |
87 | DescriptionBlock* descblock;
88 | if (targets.isEmpty()) {
89 | if (mkfile->targets().isEmpty()) {
90 | finishBuild(0);
91 | return;
92 | }
93 | descblock = mkfile->firstTarget();
94 | } else {
95 | const QString targetName = targets.first();
96 | descblock = mkfile->target(targetName);
97 | if (!descblock) {
98 | QString msg = QLatin1String("Target %1 does not exist in %2.");
99 | throw Exception(msg.arg(targetName, mkfile->fileName()));
100 | }
101 | for (int i=1; i < targets.count(); ++i) {
102 | m_pendingTargets.append( mkfile->target(targets.at(i)) );
103 | }
104 | }
105 |
106 | m_depgraph->build(descblock);
107 | if (m_makefile->options()->dumpDependencyGraph) {
108 | if (m_makefile->options()->dumpDependencyGraphDot)
109 | m_depgraph->dotDump();
110 | else
111 | m_depgraph->dump();
112 | finishBuild(0);
113 | return;
114 | }
115 |
116 | QMetaObject::invokeMethod(this, "startProcesses", Qt::QueuedConnection);
117 | }
118 |
119 | void TargetExecutor::startProcesses()
120 | {
121 | if (m_bAborted || m_jobClient->isAcquiring() || m_availableProcesses.isEmpty())
122 | return;
123 |
124 | try {
125 | if (!m_nextTarget)
126 | findNextTarget();
127 |
128 | if (m_nextTarget) {
129 | if (numberOfRunningProcesses() == 0) {
130 | // Use up the internal job token.
131 | buildNextTarget();
132 | } else {
133 | // Acquire a job token from the server. Will call buildNextTarget() when done.
134 | m_jobAcquisitionCount++;
135 | m_jobClient->asyncAcquire();
136 | }
137 | } else {
138 | if (numberOfRunningProcesses() == 0) {
139 | if (m_pendingTargets.isEmpty()) {
140 | finishBuild(0);
141 | } else {
142 | m_depgraph->clear();
143 | m_makefile->invalidateTimeStamps();
144 | m_depgraph->build(m_pendingTargets.takeFirst());
145 | QMetaObject::invokeMethod(this, "startProcesses", Qt::QueuedConnection);
146 | }
147 | }
148 | }
149 | } catch (Exception &e) {
150 | m_bAborted = true;
151 | fprintf(stderr, "Error: %s\n", qPrintable(e.message()));
152 | finishBuild(1);
153 | }
154 | }
155 |
156 | void TargetExecutor::buildNextTarget()
157 | {
158 | Q_ASSERT(m_nextTarget);
159 |
160 | if (m_bAborted)
161 | return;
162 |
163 | try {
164 | CommandExecutor *executor = m_availableProcesses.takeFirst();
165 | executor->start(m_nextTarget);
166 | m_nextTarget = 0;
167 | QMetaObject::invokeMethod(this, "startProcesses", Qt::QueuedConnection);
168 | } catch (const Exception &e) {
169 | m_bAborted = true;
170 | fprintf(stderr, "Error: %s\n", qPrintable(e.message()));
171 | finishBuild(1);
172 | }
173 | }
174 |
175 | void TargetExecutor::waitForProcesses()
176 | {
177 | foreach (CommandExecutor* process, m_processes)
178 | process->waitForFinished();
179 | }
180 |
181 | void TargetExecutor::waitForJobClient()
182 | {
183 | if (!m_jobClient->isAcquiring())
184 | return;
185 | QEventLoop loop;
186 | connect(m_jobClient, &JobClient::acquired, &loop, &QEventLoop::quit);
187 | loop.exec();
188 | m_jobClient->release();
189 | }
190 |
191 | void TargetExecutor::finishBuild(int exitCode)
192 | {
193 | if (exitCode == 0
194 | && !m_allCommandsSuccessfullyExecuted
195 | && m_makefile->options()->buildUnrelatedTargetsOnError)
196 | {
197 | // /k specified and some command failed
198 | exitCode = 1;
199 | }
200 | emit finished(exitCode);
201 | }
202 |
203 | void TargetExecutor::findNextTarget()
204 | {
205 | forever {
206 | m_nextTarget = m_depgraph->findAvailableTarget(m_makefile->options()->buildAllTargets);
207 | if (m_nextTarget) {
208 | if (m_nextTarget->m_commands.isEmpty()) {
209 | // Short cut for targets without commands.
210 | m_depgraph->removeLeaf(m_nextTarget);
211 | continue;
212 | } else if (m_makefile->options()->buildUnrelatedTargetsOnError
213 | && m_depgraph->isUnbuildable(m_nextTarget)) {
214 | fprintf(stderr, "jom: Target '%s' cannot be built due to failed dependencies.\n",
215 | qPrintable(m_nextTarget->targetName()));
216 | m_depgraph->removeLeaf(m_nextTarget);
217 | continue;
218 | }
219 | }
220 | return;
221 | }
222 | }
223 |
224 | void TargetExecutor::onChildFinished(CommandExecutor* executor, bool commandFailed)
225 | {
226 | Q_CHECK_PTR(executor->target());
227 | if (commandFailed) {
228 | m_allCommandsSuccessfullyExecuted = false;
229 | if (m_makefile->options()->buildUnrelatedTargetsOnError) {
230 | // Recursively mark all parents of this node as unbuildable due to unsatisfied
231 | // dependencies. This must happen before removing the node from the build graph.
232 | m_depgraph->markParentsRecursivlyUnbuildable(executor->target());
233 | fputs("jom: Option /K specified. Continuing.\n", stderr);
234 | }
235 | }
236 | FastFileInfo::clearCacheForFile(executor->target()->targetName());
237 | m_depgraph->removeLeaf(executor->target());
238 | if (m_jobAcquisitionCount > 0) {
239 | m_jobClient->release();
240 | m_jobAcquisitionCount--;
241 | }
242 | m_availableProcesses.append(executor);
243 | if (!executor->isBufferedOutputSet()) {
244 | executor->setBufferedOutput(true);
245 | bool found = false;
246 | foreach (CommandExecutor *cmdex, m_processes) {
247 | if (cmdex->isActive()) {
248 | cmdex->setBufferedOutput(false);
249 | found = true;
250 | }
251 | }
252 | if (!found)
253 | m_availableProcesses.first()->setBufferedOutput(false);
254 | }
255 |
256 | bool abortMakeProcess = commandFailed && !m_makefile->options()->buildUnrelatedTargetsOnError;
257 | if (abortMakeProcess) {
258 | m_bAborted = true;
259 | m_depgraph->clear();
260 | m_pendingTargets.clear();
261 | waitForProcesses();
262 | waitForJobClient();
263 | finishBuild(2);
264 | }
265 |
266 | QMetaObject::invokeMethod(this, "startProcesses", Qt::QueuedConnection);
267 | }
268 |
269 | int TargetExecutor::numberOfRunningProcesses() const
270 | {
271 | return m_processes.count() - m_availableProcesses.count();
272 | }
273 |
274 | void TargetExecutor::removeTempFiles()
275 | {
276 | foreach (QObject* child, children()) {
277 | CommandExecutor* cmdex = qobject_cast(child);
278 | if (!cmdex)
279 | continue;
280 |
281 | cmdex->cleanupTempFiles();
282 | }
283 | }
284 |
285 | } //namespace NMakeFile
286 |
--------------------------------------------------------------------------------
/src/jomlib/targetexecutor.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2016 The Qt Company Ltd.
4 | ** Contact: https://www.qt.io/licensing/
5 | **
6 | ** This file is part of jom.
7 | **
8 | ** Commercial License Usage
9 | ** Licensees holding valid commercial Qt licenses may use this file in
10 | ** accordance with the commercial license agreement provided with the
11 | ** Software or, alternatively, in accordance with the terms contained in
12 | ** a written agreement between you and The Qt Company. For licensing terms
13 | ** and conditions see https://www.qt.io/terms-conditions. For further
14 | ** information use the contact form at https://www.qt.io/contact-us.
15 | **
16 | ** GNU General Public License Usage
17 | ** Alternatively, this file may be used under the terms of the GNU
18 | ** General Public License version 3 as published by the Free Software
19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 | ** included in the packaging of this file. Please review the following
21 | ** information to ensure the GNU General Public License requirements will
22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 | **
24 | ****************************************************************************/
25 |
26 | #ifndef TARGETEXECUTOR_H
27 | #define TARGETEXECUTOR_H
28 |
29 | #include "makefile.h"
30 | #include
31 | #include
32 | #include
33 |
34 | QT_BEGIN_NAMESPACE
35 | class QFile;
36 | QT_END_NAMESPACE
37 |
38 | namespace NMakeFile {
39 |
40 | class CommandExecutor;
41 | class DependencyGraph;
42 | class JobClient;
43 |
44 | class TargetExecutor : public QObject {
45 | Q_OBJECT
46 | public:
47 | TargetExecutor(const ProcessEnvironment &environment);
48 | ~TargetExecutor();
49 |
50 | void apply(Makefile* mkfile, const QStringList& targets);
51 | void removeTempFiles();
52 |
53 | signals:
54 | void finished(int exitCode);
55 |
56 | private slots:
57 | void startProcesses();
58 | void buildNextTarget();
59 | void onChildFinished(CommandExecutor*, bool commandFailed);
60 |
61 | private:
62 | int numberOfRunningProcesses() const;
63 | void waitForProcesses();
64 | void waitForJobClient();
65 | void finishBuild(int exitCode);
66 | void findNextTarget();
67 |
68 | private:
69 | ProcessEnvironment m_environment;
70 | Makefile* m_makefile;
71 | DependencyGraph* m_depgraph;
72 | QList m_pendingTargets;
73 | JobClient *m_jobClient;
74 | bool m_bAborted;
75 | int m_jobAcquisitionCount;
76 | QList m_availableProcesses;
77 | QList m_processes;
78 | DescriptionBlock *m_nextTarget;
79 | bool m_allCommandsSuccessfullyExecuted;
80 | };
81 |
82 | } //namespace NMakeFile
83 |
84 | #endif // TARGETEXECUTOR_H
85 |
--------------------------------------------------------------------------------
/src/jomlib/use_jomlib.pri:
--------------------------------------------------------------------------------
1 | isEmpty(PROJECT_BUILD_ROOT):error(PROJECT_BUILD_ROOT must be set)
2 |
3 | win32-g++ {
4 | JOMLIB_PREFIX = lib
5 | JOMLIB_SUFFIX = a
6 | } else {
7 | JOMLIB_PREFIX =
8 | JOMLIB_SUFFIX = lib
9 | }
10 |
11 | build_pass:CONFIG(debug, debug|release) {
12 | JOMLIB = $$PROJECT_BUILD_ROOT/lib/$${JOMLIB_PREFIX}jomlibd.$$JOMLIB_SUFFIX
13 | }
14 | build_pass:CONFIG(release, debug|release) {
15 | JOMLIB = $$PROJECT_BUILD_ROOT/lib/$${JOMLIB_PREFIX}jomlib.$$JOMLIB_SUFFIX
16 | }
17 |
18 | LIBS += $$JOMLIB
19 | POST_TARGETDEPS += $$JOMLIB
20 | unset(JOMLIB)
21 |
--------------------------------------------------------------------------------
/tests/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | find_package(Qt5 5.2.0 REQUIRED COMPONENTS Test)
2 | add_executable(jom-test
3 | tests.cpp tests.h)
4 |
5 | target_link_libraries(jom-test PRIVATE jomlib Qt5::Test)
6 |
7 | add_test(NAME jom-test COMMAND jom-test)
8 |
9 | add_custom_command(TARGET jom-test POST_BUILD
10 | COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/makefiles $/makefiles
11 | )
12 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/buildUnrelatedTargetsOnError/test.mk:
--------------------------------------------------------------------------------
1 | # test the /k option
2 | # When running "jom /f test.mk /k" the target "dependsOnFailingTarget" must not be built.
3 |
4 | first: workingTarget dependsOnFailingTarget
5 |
6 | failingTarget:
7 | cmd /c exit 7
8 |
9 | dependsOnFailingTarget: failingTarget
10 | @echo We should not see this.
11 |
12 | workingTarget:
13 | @echo Yay! This always works!
14 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/builtins/cd.mk:
--------------------------------------------------------------------------------
1 | first:
2 | @echo Default target does nothing. Specify another one.
3 |
4 | provide_subdir:
5 | @if not exist subdir md subdir
6 |
7 | # expected result: this is supposed to output the subdir directory
8 | test1: provide_subdir
9 | @cd subdir
10 | @cd
11 |
12 | # expected result: this is supposed to output the subdir directory
13 | test2: provide_subdir
14 | @cd /D subdir
15 | @cd
16 |
17 | # expected result: this is supposed to output the current directory (not subdir)
18 | # Why? Because of the && nmake executes this command with cmd and loses the
19 | # current working directory after cmd completed.
20 | test3: provide_subdir
21 | @cd subdir && cd
22 | @cd
23 |
24 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/caseInsensitiveDependents/test.mk:
--------------------------------------------------------------------------------
1 | all: someFile.txt
2 |
3 | SOMEFILE.txt:
4 | @echo somefile.txt
5 |
6 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/environmentVariables/test.mk:
--------------------------------------------------------------------------------
1 | VAR1 = file
2 | all:
3 | @echo VAR1 $(VAR1)
4 | @echo VAR2 $(VAR2)
5 |
6 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/environmentVariablesCaseInsensitivity/test.mk:
--------------------------------------------------------------------------------
1 | VAR1 = $(VAR1);C:\Zort
2 | first:
3 | echo VAR1 $(VAR1) %%VAR1%%
4 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/environmentVariablesInCommands/test.mk:
--------------------------------------------------------------------------------
1 | first:
2 | set SOME_VARIABLE=narf
3 | cmd.exe /c echo %%SOME_VARIABLE%%
4 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/ignoreExitCodes/test.mk:
--------------------------------------------------------------------------------
1 | # test ignore exit codes in make files
2 |
3 | test1: testNonexistentCommand testExitCode1 testExitCode2 testExitCode3
4 | @echo ---SUCCESS---
5 |
6 | testNonexistentCommand:
7 | -nonexistent_command 2>NUL
8 |
9 | testExitCode1:
10 | -cmd /k exit 1
11 |
12 | testExitCode2:
13 | -1cmd /k exit 1
14 |
15 | testExitCode3:
16 | ------1234cmd /k exit 1234
17 |
18 | # target test2 is supposed to fail
19 | test2:
20 | -6cmd /k exit 7
21 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/inlineFiles/test.mk:
--------------------------------------------------------------------------------
1 | # test inline files in make files
2 | #
3 | # http://msdn.microsoft.com/en-us/library/1whxt45w.aspx
4 |
5 | all:
6 | @echo Please specify a target.
7 |
8 | tests: test_basic test_fileRemoval test_keepFile test_multipleFiles test_escaping
9 |
10 | init:
11 | @if exist output rmdir /s /q output
12 | @md output
13 | @echo ::post test check script > output\post_check.cmd
14 |
15 | post_check:
16 | @output\post_check.cmd
17 |
18 | test_basic: init
19 | copy << output\test_basic.txt
20 | line 1
21 | !ifndef UNDEFINED_MACRO
22 | line 2
23 | !endif
24 | line 3
25 | <<
26 |
27 | test_fileRemoval: init
28 | echo @if exist << exit /b 1 >> output\post_check.cmd
29 | some random text
30 | <<
31 | echo @if exist <> output\post_check.cmd
32 | some random text
33 | <<
34 | echo @if exist <> output\post_check.cmd
35 | some random text
36 | <> output\post_check.cmd
40 | some random text
41 | <output\test_multipleFiles.txt
45 | one
46 | two
47 | <<
48 | three
49 | four
50 | <<
51 |
52 | test_escaping: init
53 | copy << output\test_escaping.txt
54 | InRoot$$$$Sections
55 | # This line should be there.
56 | <<
57 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/inlineFiles/test_basic_expected.txt:
--------------------------------------------------------------------------------
1 | line 1
2 | line 2
3 | line 3
4 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/inlineFiles/test_escaping_expected.txt:
--------------------------------------------------------------------------------
1 | InRoot$$Sections
2 | # This line should be there.
3 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/inlineFiles/test_multipleFiles_expected.txt:
--------------------------------------------------------------------------------
1 | one
2 | two
3 | three
4 | four
5 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/macrosOnCommandLine/test.mk:
--------------------------------------------------------------------------------
1 | FooBar = 1
2 | !message FooBar:$(FooBar)
3 | !message FOOBAR:$(FOOBAR)
4 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/noTargets/test.mk:
--------------------------------------------------------------------------------
1 | !message Hello there!
2 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/nonexistentdependent/test.mk:
--------------------------------------------------------------------------------
1 | out: yo notexist
2 | @echo we should not see this
3 |
4 | yo:
5 | @echo yo ho ho ho
6 |
7 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/outofdatecheck/test.mk:
--------------------------------------------------------------------------------
1 | all: one.txt two three four five six
2 |
3 | clean:
4 | @del one.txt two.txt three.txt four.txt six.txt > NUL 2>&1
5 |
6 | one.txt:
7 | @echo $@
8 | @echo $@ > $@
9 | # @ping 127.0.0.1 -n 2 -w 1000 > nul
10 |
11 | two: two.txt
12 | @echo $@
13 |
14 | two-without-commands: two.txt
15 |
16 | two.txt:
17 | @echo $@
18 | @echo $@ > $@
19 | # @ping 127.0.0.1 -n 2 -w 1000 > nul
20 |
21 | three: three.txt
22 | @echo $@
23 |
24 | # Insane nmake behavior:
25 | # three.txt is always built because 'two' has commands.
26 | three.txt: two
27 | @echo $@
28 | @type two.txt > $@
29 | # @ping 127.0.0.1 -n 2 -w 1000 > nul
30 |
31 | four: four.txt
32 | @echo $@
33 |
34 | four.txt: two.txt
35 | @echo $@
36 | @copy two.txt $@ > NUL
37 | # @ping 127.0.0.1 -n 2 -w 1000 > nul
38 |
39 | five:
40 | @echo $@
41 |
42 | six: six.txt
43 | @echo $@
44 |
45 | # Insane nmake behavior:
46 | # six.txt is only built when two.txt has changed because 'two-without-commands'
47 | # is a real pseudotarget.
48 | six.txt: two-without-commands
49 | @echo $@
50 | @type two.txt > $@
51 |
52 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/suffixes/one.a:
--------------------------------------------------------------------------------
1 | foo
2 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/suffixes/one.b:
--------------------------------------------------------------------------------
1 | foo
2 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/suffixes/one.c:
--------------------------------------------------------------------------------
1 | foo
2 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/suffixes/test.mk:
--------------------------------------------------------------------------------
1 | .SUFFIXES:
2 | .SUFFIXES: .a .b .c .d
3 |
4 | .a.x:
5 | @echo a -^> x
6 | .b.x:
7 | @echo b -^> x
8 | .c.x:
9 | @echo c -^> x
10 |
11 | all: one two.x three.x
12 | one: one.x
13 | two.x: one.x
14 | three.x: two.x
15 |
16 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/suffixes/three.c:
--------------------------------------------------------------------------------
1 | foo
2 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/suffixes/three.d:
--------------------------------------------------------------------------------
1 | foo
2 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/suffixes/two.b:
--------------------------------------------------------------------------------
1 | foo
2 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/suffixes/two.c:
--------------------------------------------------------------------------------
1 | foo
2 |
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/unicodeFiles/test_utf16.mk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qt-labs/jom/5b295dbee66504d21b8cc7d05d5e88e87644d586/tests/makefiles/blackbox/unicodeFiles/test_utf16.mk
--------------------------------------------------------------------------------
/tests/makefiles/blackbox/unicodeFiles/test_utf8.mk:
--------------------------------------------------------------------------------
1 | # file encoding: UTF8 with signature
2 |
3 | all:
4 | if not exist "куда Я прошу" md "куда Я прошу"
5 | cd "куда Я прошу"
6 | cd ..
7 |
--------------------------------------------------------------------------------
/tests/makefiles/circular_include.mk:
--------------------------------------------------------------------------------
1 | !include circular_Include2.mk
2 | CIRCULAR_INCLUDE = TRUE
3 |
4 |
--------------------------------------------------------------------------------
/tests/makefiles/circular_include2.mk:
--------------------------------------------------------------------------------
1 | !include circular_Include.mk
2 | CIRCULAR_INCLUDE2 = TRUE
3 |
4 |
--------------------------------------------------------------------------------
/tests/makefiles/commandmodifiers.mk:
--------------------------------------------------------------------------------
1 | first: dep1 dep2
2 | @echo silent command
3 | -echo no error checking
4 | -5echo maximum exit code is 5
5 | -15echo maximum exit code is 15
6 | !echo command for each dependent $**
7 |
8 | dep1:
9 | dep2:
10 |
--------------------------------------------------------------------------------
/tests/makefiles/comments.mk:
--------------------------------------------------------------------------------
1 | # this is just a comment
2 | !IF 1 # - 1
3 | COMPILER = Ada95 # here's a comment after a macro definition
4 | DEF = ^#define # ignore me
5 |
6 | first: second third # la la la la
7 | echo I'm Winneone
8 | # foooooo
9 | # baaaaar
10 | echo I'm Winnetou
11 | # Wie viele Winnes haben wir in gesamt?
12 | second:
13 | third:
14 |
15 | .cpp.obj: # and another one
16 | echo inference rule applied
17 |
18 | forth: fifth ; echo # this is no comment
19 | echo # this neither
20 | fifth: file^#99.txt # This is a comment!
21 | echo $**
22 | !ENDIF
23 |
24 | .SILENT: # comment after dot directive
25 |
26 |
--------------------------------------------------------------------------------
/tests/makefiles/conditionals.mk:
--------------------------------------------------------------------------------
1 | TEST1=false
2 | !if 1
3 | TEST1=true
4 | !elseif 0
5 | TEST1=false
6 | !elseif 0
7 | TEST1=false
8 | !endif
9 |
10 | TEST2=false
11 | !if 0
12 | TEST2=false
13 | !elseif 0
14 | # some comment
15 | # more to say...
16 | NOOP=1
17 | TEST2=false
18 | !elseif 1
19 | NOOP=1
20 | TEST2=true
21 | NOOP=1
22 | !endif
23 |
24 | TEST3=false
25 | !if 0 # comment
26 | TEST3=false
27 | !elseif 1#another comment
28 | TEST3=true
29 | !elseif 1 # comment
30 | TEST3=false
31 | !endif
32 |
33 | TEST4=false
34 | !IFDEF TEST1
35 | TEST4=true
36 | !ELSEIFDEF NOT_DEFINED
37 | TEST4=false
38 | !ELSE
39 | TEST4=false
40 | !ENDIF
41 |
42 | TEST5=false
43 | !IFDEF NOT_DEFINED
44 | TEST5=false
45 | !ELSEIFDEF TEST1
46 | TEST5=true
47 | !ELSE
48 | TEST5=false
49 | !ENDIF
50 |
51 | TEST6=false
52 | !IFDEF NOT_DEFINED
53 | TEST6=false
54 | !ELSEIFDEF NOT_DEFINED
55 | TEST6=false
56 | !ELSE
57 | TEST6=true
58 | !ENDIF
59 |
60 | TEST7=false
61 | !IFDEF NOT_DEFINED
62 | TEST7=false
63 | !ELSEIFNDEF NOT_DEFINED
64 | TEST7=true
65 | !ELSE
66 | TEST7=false
67 | !ENDIF
68 |
69 | TEST8=false
70 | !IFNDEF NOT_DEFINED
71 | TEST8=true
72 | !ELSEIFNDEF NOT_DEFINED
73 | TEST8=false
74 | !ELSE
75 | TEST8=false
76 | !ENDIF
77 |
78 | TEST9=foo \
79 | bar \
80 | !IF 1
81 | baz \
82 | !ELSE
83 | boo \
84 | hoo
85 | !ENDIF
86 |
87 | TEST10=foo \
88 | bar \
89 | !IF 0
90 | baz \
91 | !ELSE
92 | boo \
93 | hoo
94 | !ENDIF
95 |
96 | all:
97 |
98 |
--------------------------------------------------------------------------------
/tests/makefiles/cycle_in_targets.mk:
--------------------------------------------------------------------------------
1 | first: foo
2 |
3 | foo: bar
4 |
5 | bar: schnusel
6 |
7 | schnusel: foo
8 |
9 |
--------------------------------------------------------------------------------
/tests/makefiles/depswithspace.mk:
--------------------------------------------------------------------------------
1 | first: one "dependent two with spaces" three
2 | echo $**
3 |
4 | one:
5 | "dependent two with spaces":
6 | three:
7 |
8 |
--------------------------------------------------------------------------------
/tests/makefiles/descriptionblocks.mk:
--------------------------------------------------------------------------------
1 | all : one two three dollarSigns
2 |
3 | DEPENDENT_C=c
4 |
5 | one: a b $(DEPENDENT_C)
6 | @echo one
7 | two:; @echo two
8 | three : "a;b" ;@echo three; @echo end of three
9 | four: ; @echo four=4
10 |
11 | a :
12 | b :
13 | c :
14 | "a;b":
15 | @echo X
16 |
17 | DIRECTORYNAME=.
18 | $(DIRECTORYNAME):
19 | @echo directory $(DIRECTORYNAME) doesn't exist. That's strange.
20 | "$(DIRECTORYNAME)":
21 | @echo directory "$(DIRECTORYNAME)" doesn't exist. That's strange.
22 |
23 | DIRECTORYNAME=..
24 | $(DIRECTORYNAME):
25 | @echo directory $(DIRECTORYNAME) doesn't exist. That's strange.
26 | "$(DIRECTORYNAME)":
27 | @echo directory "$(DIRECTORYNAME)" doesn't exist. That's strange.
28 |
29 | dollarSigns:
30 | @echo ($$dollar-signs$$)
31 | @echo $$(dollar-signs)$$
32 |
33 | TARGETNAME=XTargetName
34 | $(TARGETNAME:X=Substituted): dep1 dep2 dep3
35 | @echo target name with macro substitution
36 |
--------------------------------------------------------------------------------
/tests/makefiles/dotdirectives.mk:
--------------------------------------------------------------------------------
1 | all: silence ignorance preciousness suffixes
2 |
3 | silence: silence_one silence_two silence_three
4 | silence_one:
5 | echo 1
6 | $(NOT_DEFINED).SILENT:
7 | silence_two:
8 | echo 2
9 | $(NOT_DEFINED)!CMDSWITCHES -S
10 | silence_three:
11 | echo 3
12 |
13 | ignorance: ignorance_one ignorance_two ignorance_three
14 | ignorance_one:
15 | echo 1
16 | $(NOT_DEFINED).IGNORE :
17 | ignorance_two:
18 | echo 2
19 | cmd /c exit /b 1
20 | $(NOT_DEFINED)! CMDSWITCHES -i
21 | ignorance_three:
22 | echo 3
23 |
24 | preciousness: preciousness_one preciousness_two preciousness_three
25 | $(NOT_DEFINED).PRECIOUS : preciousness_one preciousness_two preciousness_three
26 | preciousness_one:
27 | preciousness_two:
28 | preciousness_three:
29 |
30 | $(NOT_DEFINED).SUFFIXES: .exe .obj
31 | suffixes:
32 |
--------------------------------------------------------------------------------
/tests/makefiles/file#99.txt:
--------------------------------------------------------------------------------
1 | What a nice file name.
2 |
--------------------------------------------------------------------------------
/tests/makefiles/fileNameMacrosInDependents.mk:
--------------------------------------------------------------------------------
1 | all:
2 | DEPS=$@ $$@ $* $(@D) $$(@D) $(*D) $(@B) $$(@B) $(*B) $(@F) $$(@F) $(*F) $(@R) $$(@R) $(*R)
3 | foo: $(DEPS)
4 | foo.obj: $(DEPS)
5 | C:\MyProject\tmp\foo.obj: $(DEPS)
6 | "C:\My Project\tmp\foo.obj": $(DEPS)
7 |
--------------------------------------------------------------------------------
/tests/makefiles/filenamemacros.mk:
--------------------------------------------------------------------------------
1 | all: Footb$$@ LolCatExtractorManager.tar.gz manyDependents \
2 | manyDependentsSingleExecution manyDependentsSubstitutedNames \
3 | manyDependentsInlineFile \
4 | gen_init generated.txt gen_cleanup macros.mk $(MAKEDIR)\infrules.mk \
5 | root_dir\substitutionWithColon nonexistenttarget
6 |
7 | # $** and $? are undefined here and should be evaluated to empty strings.
8 | Football:
9 | @echo $$@
10 | @echo $@ $@
11 | @echo $$** $**
12 | @echo $$? $?
13 | @echo $$(**) $(**)
14 | @echo $$(?) $(?)
15 |
16 | LolCatExtractorManager.tar.gz:
17 | @echo $*
18 |
19 | dependencyWithSpaces: foo "broken arrow" bar
20 | @echo $$** $**
21 |
22 | manyDependents: "Mr. Garrison" Timmy Jimmy Kenny Eric Kyle Stan
23 | @echo $**
24 | @echo $?
25 |
26 | manyDependentsSingleExecution: "Mr. Garrison" Timmy Jimmy Kenny Eric Kyle Stan
27 | !@echo $**
28 | !@echo $?
29 |
30 | manyDependentsSubstitutedNames: Tilly Jilly
31 | @echo $$(**) $(**)
32 | @echo $$(?) $(?)
33 | @echo $$(**:ll=mm) $(**:ll=mm)
34 | @echo $$(?:ll=mm) $(?:ll=mm)
35 |
36 | manyDependentsInlineFile: Timmy Jimmy Kenny Eric Kyle Stan
37 | @type <<
38 | $$@ $@
39 | $$** $**
40 | <<
41 |
42 | manyDependentsWithModifiers: subdir\Timmy.txt subdir\subsubdir\Jimmy.txt Kenny.txt Eric.txt Kyle.txt Stan.txt
43 | @echo $$(**D) $(**D)
44 | @echo $$(**B) $(**B)
45 | @echo $$(**F) $(**F)
46 | @echo $$(**R) $(**R)
47 | @echo $$(?D) $(?D)
48 | @echo $$(?B) $(?B)
49 | @echo $$(?F) $(?F)
50 | @echo $$(?R) $(?R)
51 |
52 | Timmy:
53 | Jimmy:
54 | Kenny:
55 | Eric:
56 | Kyle:
57 | Stan:
58 | Tilly:
59 | Jilly:
60 |
61 | subdir\Timmy.txt:
62 | subdir\subsubdir\Jimmy.txt:
63 | Kenny.txt:
64 | Eric.txt:
65 | Kyle.txt:
66 | Stan.txt:
67 | Tilly.txt:
68 | Jilly.txt:
69 |
70 | gen_init:
71 | @echo x > gen1.txt
72 | @echo x > generated.txt
73 | @echo x > gen2.txt
74 | @echo x > gen3.txt
75 |
76 | generated.txt: gen1.txt gen2.txt gen3.txt
77 | @echo $?
78 |
79 | gen_cleanup:
80 | @del generated.txt gen?.txt
81 |
82 | macros.mk:
83 | @echo $$(@D) $(@D)
84 | @echo $$(@B) $(@B)
85 | @echo $$(@F) $(@F)
86 | @echo $$(@R) $(@R)
87 |
88 | $(MAKEDIR)\infrules.mk: force
89 | @echo $$(@D) $(@D)
90 | @echo $$(@B) $(@B)
91 | @echo $$(@F) $(@F)
92 | @echo $$(@R) $(@R)
93 |
94 | force:
95 |
96 | root_dir\substitutionWithColon:
97 | @echo $(@:root_dir=C:\somewhere)
98 | @echo $(@R:root_dir=C:\somewhere)
99 |
100 | nonexistenttarget: filenamemacros.mk
101 | @echo $$? $?
102 |
--------------------------------------------------------------------------------
/tests/makefiles/foo1.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qt-labs/jom/5b295dbee66504d21b8cc7d05d5e88e87644d586/tests/makefiles/foo1.cpp
--------------------------------------------------------------------------------
/tests/makefiles/foo3.cpp:
--------------------------------------------------------------------------------
1 | I am temporary. Delete me.
2 |
--------------------------------------------------------------------------------
/tests/makefiles/foo4.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qt-labs/jom/5b295dbee66504d21b8cc7d05d5e88e87644d586/tests/makefiles/foo4.cpp
--------------------------------------------------------------------------------
/tests/makefiles/include1.mk:
--------------------------------------------------------------------------------
1 | # Make sure that this file does NOT have a newline at the end!
2 | !message "include 1"
3 | INCLUDE1=TRUE
--------------------------------------------------------------------------------
/tests/makefiles/include2.mk:
--------------------------------------------------------------------------------
1 | !message "include 2"
2 | INCLUDE2=TRUE
3 |
4 |
--------------------------------------------------------------------------------
/tests/makefiles/include5.mk:
--------------------------------------------------------------------------------
1 | !message "include 5"
2 | INCLUDE5 = TRUE
3 |
4 |
--------------------------------------------------------------------------------
/tests/makefiles/include_test.mk:
--------------------------------------------------------------------------------
1 | !include $(NOT_DEFINED)include1.mk
2 | include include2.mk # old style include directive
3 |
4 | INCLUDE = $(INCLUDE);subdir
5 | ! include
6 | !include "subdir\include4.mk"
7 | !include <"include9.mk">
8 |
9 | includeFoo: # this is not an include directive!
10 |
11 |
--------------------------------------------------------------------------------
/tests/makefiles/infrules.mk:
--------------------------------------------------------------------------------
1 | DEPNAME=($<)
2 |
3 | $(NOT_DEFINED).cpp$(NOT_DEFINED).obj:
4 | @echo .cpp.obj $(DEPNAME)
5 |
6 | {subdir}.cpp.obj:
7 | @echo {subdir}.cpp.obj ($<)
8 |
9 | all: init\
10 | foo1.obj foo2.obj foo3.obj foo4.obj\
11 | foo5.obj "foo6.obj" foo.bar.obj\
12 | cleanup
13 |
14 | init:
15 | @echo I am temporary. Delete me. > foo6.cpp
16 | @echo I am temporary. Delete me. > foo5.cpp
17 | @echo I am temporary. Delete me. > subdir\foo5.cpp
18 | @echo I am temporary. Delete me. > foo.bar.cpp
19 |
20 | cleanup:
21 | @del foo6.cpp
22 | @del foo5.cpp
23 | @del subdir\foo5.cpp
24 | @del foo.bar.cpp
25 |
26 | foo4.obj: foo4.cpp
27 |
28 | foo5.obj: foo5.cpp
29 |
30 | "foo6.obj": foo6.cpp
31 |
32 | foo.bar.obj: foo.bar.cpp
33 |
34 |
--------------------------------------------------------------------------------
/tests/makefiles/macrotest.mk:
--------------------------------------------------------------------------------
1 | VERY_LONG_Macro_Name_With_mucho_mucho_characters_and_some_number_too_1234458789765421200218427824996512548989654486630110059699471421 = AHA
2 | LOREM = ipsum
3 | SEIN = ist
4 | DES = kleinen
5 | WUPPIWUPPI = wallewalle
6 | ThisIsNotDefined=well, at the moment is actually *is* defined.
7 | viel$(LOREM)_$(SEIN)$(WUPPIWUPPI)_ = Icke wa dsch und er denn uurrrgh...
8 | # what about a comment inbetween? good idea! :-)
9 | NoContent= # this is a comment, dude
10 | LateDefinition = _$(Literal2)_
11 | Literal1 = ^# who does that anyway? ^# # but here ends the line, sucker!
12 | Literal2 = thi$$ i$$ pricele$$$$
13 | Literal3 = schnupsi^
14 | wupsi^
15 | dupsi
16 | Literal4 = backslash at the end^\
17 | !UNDEF ThisIsNotDefined
18 | Literal5 = backslash at the end\#
19 | Literal6 = backslash at the end\ # errm i don't have anything to say...
20 | Literal7 = double backslash at the end\\
21 | SplitOverLines= \
22 | one \
23 | two\
24 | three
25 | Incremental = one
26 | Incremental = $(Incremental) two
27 |
28 | B=B
29 | y=y
30 | $BANANA=$yellow
31 |
32 | 1=x
33 | XXX=$1$(1)$1
34 |
35 | MACROSUBSTITUTION=is not working
36 | MKSPECDIR=root_dir\mkspecs
37 |
38 | _STARTING_WITH_AN_UNDERSCORE=underscores are beautiful
39 | __STARTING_WITH_TWO_UNDERSCORES=underscores are beautiful
40 |
--------------------------------------------------------------------------------
/tests/makefiles/subdir/foo1.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qt-labs/jom/5b295dbee66504d21b8cc7d05d5e88e87644d586/tests/makefiles/subdir/foo1.cpp
--------------------------------------------------------------------------------
/tests/makefiles/subdir/foo2.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qt-labs/jom/5b295dbee66504d21b8cc7d05d5e88e87644d586/tests/makefiles/subdir/foo2.cpp
--------------------------------------------------------------------------------
/tests/makefiles/subdir/foo4.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qt-labs/jom/5b295dbee66504d21b8cc7d05d5e88e87644d586/tests/makefiles/subdir/foo4.cpp
--------------------------------------------------------------------------------
/tests/makefiles/subdir/include3.mk:
--------------------------------------------------------------------------------
1 | !message "include 3"
2 | INCLUDE3 = TRUE
3 |
4 |
--------------------------------------------------------------------------------
/tests/makefiles/subdir/include4.mk:
--------------------------------------------------------------------------------
1 | !message "include 4"
2 | INCLUDE4 = TRUE
3 | !include include5.mk
4 | !include subdir\subsub\include6.mk
5 |
--------------------------------------------------------------------------------
/tests/makefiles/subdir/include7.mk:
--------------------------------------------------------------------------------
1 | !message "include 7"
2 | INCLUDE7 = TRUE
3 |
4 |
--------------------------------------------------------------------------------
/tests/makefiles/subdir/include8.mk:
--------------------------------------------------------------------------------
1 | !message "include 8"
2 | INCLUDE8 = TRUE
3 |
4 |
--------------------------------------------------------------------------------
/tests/makefiles/subdir/include9.mk:
--------------------------------------------------------------------------------
1 | !message "include 9"
2 | INCLUDE9 = TRUE
3 |
4 |
--------------------------------------------------------------------------------
/tests/makefiles/subdir/subsub/include6.mk:
--------------------------------------------------------------------------------
1 | !message "include 6"
2 | INCLUDE6=TRUE
3 | !include include7.mk
4 | !include "include8.mk"
5 |
--------------------------------------------------------------------------------
/tests/makefiles/targetmultidef.mk:
--------------------------------------------------------------------------------
1 | all: foo bar
2 |
3 | foo: foo1.cpp
4 | foo: foo3.cpp
5 | foo: foo4.cpp
6 | echo $**
7 |
8 | bar:: foo1.cpp
9 | echo one
10 | bar:: foo3.cpp
11 | echo two
12 | bar:: foo4.cpp
13 | echo three
14 |
15 |
--------------------------------------------------------------------------------
/tests/makefiles/wildcardsInDependencies.mk:
--------------------------------------------------------------------------------
1 | all: *.txt foo?.cpp
2 | more: subdir\*.cpp
3 |
--------------------------------------------------------------------------------
/tests/makefiles/windowspaths.mk:
--------------------------------------------------------------------------------
1 | C:\foo.txt:
2 | @echo $@
3 |
4 | C:/bar.txt:
5 | @echo $@
6 |
7 | "C:\three.txt"::
8 | @echo $@
9 |
10 | C:\three.txt::
11 | @echo ...
12 |
13 | S ::
14 | @echo $@
15 |
16 | "S" ::
17 | @echo ...
18 |
--------------------------------------------------------------------------------
/tests/tests.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | **
3 | ** Copyright (C) 2015 The Qt Company Ltd.
4 | ** Contact: http://www.qt.io/licensing/
5 | **
6 | ** This file is part of the jom project on Trolltech Labs.
7 | **
8 | ** This file may be used under the terms of the GNU General Public
9 | ** License version 2.0 or 3.0 as published by the Free Software Foundation
10 | ** and appearing in the file LICENSE.GPL included in the packaging of
11 | ** this file. Please review the following information to ensure GNU
12 | ** General Public Licensing requirements will be met:
13 | ** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
14 | ** http://www.gnu.org/copyleft/gpl.html.
15 | **
16 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
17 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 | **
19 | ****************************************************************************/
20 |
21 | #ifndef TESTS_H
22 | #define TESTS_H
23 |
24 | #include
25 | #include
26 | #include
27 |
28 | namespace NMakeFile
29 | {
30 | class Preprocessor;
31 | class MakefileFactory;
32 | }
33 |
34 | class Tests : public QObject
35 | {
36 | Q_OBJECT
37 | private slots:
38 | void initTestCase();
39 | void cleanupTestCase();
40 |
41 | // preprocessor tests
42 | void includeFiles();
43 | void includeCycle();
44 | void macros();
45 | void invalidMacros_data();
46 | void invalidMacros();
47 | void preprocessorExpressions_data();
48 | void preprocessorExpressions();
49 | void preprocessorDivideByZero();
50 | void preprocessorInvalidExpressions_data();
51 | void preprocessorInvalidExpressions();
52 | void conditionals();
53 | void dotDirectives();
54 |
55 | // parser tests
56 | void descriptionBlocks();
57 | void inferenceRules_data();
58 | void inferenceRules();
59 | void cycleInTargets();
60 | void dependentsWithSpace();
61 | void multipleTargets();
62 | void commandModifiers();
63 | void comments();
64 | void fileNameMacros();
65 | void fileNameMacrosInDependents();
66 | void wildcardsInDependencies();
67 | void windowsPathsInTargetName();
68 |
69 | // black-box tests
70 | void buildUnrelatedTargetsOnError();
71 | void caseInsensitiveDependents();
72 | void environmentVariables_data();
73 | void environmentVariables();
74 | void environmentVariablesCaseInsensitivity();
75 | void environmentVariablesInCommands();
76 | void ignoreExitCodes();
77 | void inlineFiles();
78 | void unicodeFiles_data();
79 | void unicodeFiles();
80 | void builtin_cd_data();
81 | void builtin_cd();
82 | void suffixes();
83 | void macrosOnCommandLine_data();
84 | void macrosOnCommandLine();
85 | void nonexistentDependent();
86 | void noTargets();
87 | void outOfDateCheck();
88 |
89 | private:
90 | bool openMakefile(const QString& fileName);
91 | bool runJom(const QStringList &args, const QString &workingDirectory = QString(),
92 | QProcess::ProcessChannelMode channelMode = QProcess::MergedChannels);
93 | bool fileContentsEqual(const QString& fileName1, const QString& fileName2);
94 | QStringList readJomStdOutput();
95 | void touchFile(const QString &fileName);
96 | static QList splitOutput(const QByteArray &output);
97 |
98 | private:
99 | QString m_oldCurrentPath;
100 | NMakeFile::Preprocessor* m_preprocessor;
101 | NMakeFile::MakefileFactory* m_makefileFactory;
102 | QProcess *m_jomProcess;
103 | };
104 |
105 | #endif // TESTS_H
106 |
--------------------------------------------------------------------------------
/tests/tests.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = app
2 | QT = core testlib
3 | INCLUDEPATH += ../src/jomlib
4 |
5 | CONFIG(debug, debug|release) {
6 | TARGET = testsd
7 | } else {
8 | TARGET = tests
9 | }
10 |
11 | PROJECT_BUILD_ROOT=$$OUT_PWD/..
12 | include(../src/jomlib/use_jomlib.pri)
13 |
14 | contains(QMAKE_CXXFLAGS_RELEASE, -MT) {
15 | QMAKE_LFLAGS_RELEASE += /NODEFAULTLIB:msvcrt
16 | }
17 |
18 | HEADERS += tests.h
19 | SOURCES += tests.cpp
20 |
21 | OTHER_FILES += $$files(makefiles/*, true)
22 |
--------------------------------------------------------------------------------