Skip to content

Commit

Permalink
Merge branch 'master' into v2
Browse files Browse the repository at this point in the history
  • Loading branch information
jhasse committed Jan 17, 2025
2 parents 973b20d + 6b5d7a7 commit cc4802c
Show file tree
Hide file tree
Showing 30 changed files with 396 additions and 257 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:

jobs:
build:
runs-on: macos-12
runs-on: macos-13

steps:
- uses: actions/checkout@v4
Expand Down
3 changes: 2 additions & 1 deletion configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,11 +329,12 @@ def search_system_path(file_name: str) -> Optional[str]: # type: ignore # Missi
raise Exception('cl.exe not found. Run again from the Developer Command Prompt for VS')
cflags = ['/showIncludes',
'/nologo', # Don't print startup banner.
'/utf-8',
'/Zi', # Create pdb with debug info.
'/W4', # Highest warning level.
'/WX', # Warnings as errors.
'/wd4530', '/wd4100', '/wd4706', '/wd4244',
'/wd4512', '/wd4800', '/wd4702', '/wd4819',
'/wd4512', '/wd4800', '/wd4702',
# Disable warnings about constant conditional expressions.
'/wd4127',
# Disable warnings about passing "this" during initialization.
Expand Down
83 changes: 78 additions & 5 deletions misc/output_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,18 @@ class Output(unittest.TestCase):
'',
))

def _test_expected_error(self, plan: str, flags: T.Optional[str], expected: str):
def _test_expected_error(self, plan: str, flags: T.Optional[str],expected: str,
*args, exit_code: T.Optional[int]=None, **kwargs)->None:
"""Run Ninja with a given plan and flags, and verify its cooked output against an expected content.
All *args and **kwargs are passed to the `run` function
"""
actual = ''
try:
actual = run(plan, flags, print_err_output=False)
except subprocess.CalledProcessError as err:
actual = err.cooked_output
kwargs['print_err_output'] = False
with self.assertRaises(subprocess.CalledProcessError) as cm:
run(plan, flags, *args, **kwargs)
actual = cm.exception.cooked_output
if exit_code is not None:
self.assertEqual(cm.exception.returncode, exit_code)
self.assertEqual(expected, actual)

def test_issue_1418(self) -> None:
Expand Down Expand Up @@ -281,6 +285,75 @@ def test_issue_2048(self) -> None:
except subprocess.CalledProcessError as err:
self.fail("non-zero exit code with: " + err.output)

def test_pr_2540(self)->None:
py = sys.executable
plan = f'''\
rule CUSTOM_COMMAND
command = $COMMAND
build 124: CUSTOM_COMMAND
COMMAND = {py} -c 'exit(124)'
build 127: CUSTOM_COMMAND
COMMAND = {py} -c 'exit(127)'
build 130: CUSTOM_COMMAND
COMMAND = {py} -c 'exit(130)'
build 137: CUSTOM_COMMAND
COMMAND = {py} -c 'exit(137)'
build success: CUSTOM_COMMAND
COMMAND = sleep 0.3; echo success
'''
# Disable colors
env = default_env.copy()
env['TERM'] = 'dumb'
self._test_expected_error(
plan, '124',
f'''[1/1] {py} -c 'exit(124)'
FAILED: [code=124] 124 \n{py} -c 'exit(124)'
ninja: build stopped: subcommand failed.
''',
exit_code=124, env=env,
)
self._test_expected_error(
plan, '127',
f'''[1/1] {py} -c 'exit(127)'
FAILED: [code=127] 127 \n{py} -c 'exit(127)'
ninja: build stopped: subcommand failed.
''',
exit_code=127, env=env,
)
self._test_expected_error(
plan, '130',
'ninja: build stopped: interrupted by user.\n',
exit_code=130, env=env,
)
self._test_expected_error(
plan, '137',
f'''[1/1] {py} -c 'exit(137)'
FAILED: [code=137] 137 \n{py} -c 'exit(137)'
ninja: build stopped: subcommand failed.
''',
exit_code=137, env=env,
)
self._test_expected_error(
plan, 'non-existent-target',
"ninja: error: unknown target 'non-existent-target'\n",
exit_code=1, env=env,
)
self._test_expected_error(
plan, '-j2 success 127',
f'''[1/2] {py} -c 'exit(127)'
FAILED: [code=127] 127 \n{py} -c 'exit(127)'
[2/2] sleep 0.3; echo success
success
ninja: build stopped: subcommand failed.
''',
exit_code=127, env=env,
)

def test_depfile_directory_creation(self) -> None:
b = BuildDir('''\
rule touch
Expand Down
28 changes: 19 additions & 9 deletions src/build.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "depfile_parser.h"
#include "deps_log.h"
#include "disk_interface.h"
#include "exit_status.h"
#include "explanations.h"
#include "graph.h"
#include "metrics.h"
Expand Down Expand Up @@ -687,7 +688,7 @@ bool Builder::AlreadyUpToDate() const {
return !plan_.more_to_do();
}

bool Builder::Build(string* err) {
ExitStatus Builder::Build(string* err) {
assert(!AlreadyUpToDate());
plan_.PrepareQueue();

Expand Down Expand Up @@ -726,14 +727,14 @@ bool Builder::Build(string* err) {
if (!StartEdge(edge, err)) {
Cleanup();
status_->BuildFinished();
return false;
return ExitFailure;
}

if (edge->is_phony()) {
if (!plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, err)) {
Cleanup();
status_->BuildFinished();
return false;
return ExitFailure;
}
} else {
++pending_commands;
Expand All @@ -760,14 +761,16 @@ bool Builder::Build(string* err) {
Cleanup();
status_->BuildFinished();
*err = "interrupted by user";
return false;
return result.status;
}

--pending_commands;
if (!FinishCommand(&result, err)) {
bool command_finished = FinishCommand(&result, err);
SetFailureCode(result.status);
if (!command_finished) {
Cleanup();
status_->BuildFinished();
return false;
return result.status;
}

if (!result.success()) {
Expand All @@ -791,11 +794,11 @@ bool Builder::Build(string* err) {
else
*err = "stuck [this is a bug]";

return false;
return GetExitCode();
}

status_->BuildFinished();
return true;
return ExitSuccess;
}

bool Builder::StartEdge(Edge* edge, string* err) {
Expand Down Expand Up @@ -883,7 +886,7 @@ bool Builder::FinishCommand(CommandRunner::Result* result, string* err) {
running_edges_.erase(it);

status_->BuildEdgeFinished(edge, start_time_millis, end_time_millis,
result->success(), result->output);
result->status, result->output);

// The rest of this function only applies to successful commands.
if (!result->success()) {
Expand Down Expand Up @@ -1036,3 +1039,10 @@ bool Builder::LoadDyndeps(Node* node, string* err) {

return true;
}

void Builder::SetFailureCode(ExitStatus code) {
// ExitSuccess should not overwrite any error
if (code != ExitSuccess) {
exit_code_ = code;
}
}
12 changes: 10 additions & 2 deletions src/build.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,9 @@ struct Builder {
/// Returns true if the build targets are already up to date.
bool AlreadyUpToDate() const;

/// Run the build. Returns false on error.
/// Run the build. Returns ExitStatus or the exit code of the last failed job.
/// It is an error to call this function when AlreadyUpToDate() is true.
bool Build(std::string* err);
ExitStatus Build(std::string* err);

bool StartEdge(Edge* edge, std::string* err);

Expand All @@ -234,6 +234,10 @@ struct Builder {
std::unique_ptr<CommandRunner> command_runner_;
Status* status_;

/// Returns ExitStatus or the exit code of the last failed job
/// (doesn't need to be an enum value of ExitStatus)
ExitStatus GetExitCode() const { return exit_code_; }

private:
bool ExtractDeps(CommandRunner::Result* result, const std::string& deps_type,
const std::string& deps_prefix,
Expand All @@ -254,6 +258,10 @@ struct Builder {

DependencyScan scan_;

/// Keep the global exit code for the build
ExitStatus exit_code_ = ExitSuccess;
void SetFailureCode(ExitStatus code);

// Unimplemented copy ctor and operator= ensure we don't copy the auto_ptr.
Builder(const Builder &other); // DO NOT IMPLEMENT
void operator=(const Builder &other); // DO NOT IMPLEMENT
Expand Down
Loading

0 comments on commit cc4802c

Please sign in to comment.