aboutsummaryrefslogtreecommitdiff
path: root/scripts/cmake/vcpkg_execute_build_process.cmake
blob: 98e3648d506dd5f7bb1e949ead809543407faf5e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
## # vcpkg_execute_build_process
##
## Execute a required build process
##
## ## Usage
## ```cmake
## vcpkg_execute_build_process(
##     COMMAND <cmd> [<args>...]
##     [NO_PARALLEL_COMMAND <cmd> [<args>...]]
##     WORKING_DIRECTORY </path/to/dir>
##     LOGNAME <log_name>)
## )
## ```
## ## Parameters
## ### COMMAND
## The command to be executed, along with its arguments.
##
## ### NO_PARALLEL_COMMAND
## Optional parameter which specifies a non-parallel command to attempt if a
## failure potentially due to parallelism is detected.
##
## ### WORKING_DIRECTORY
## The directory to execute the command in.
##
## ### LOGNAME
## The prefix to use for the log files.
##
## This should be a unique name for different triplets so that the logs don't
## conflict when building multiple at once.
##
## ## Examples
##
## * [icu](https://github.com/Microsoft/vcpkg/blob/master/ports/icu/portfile.cmake)
include(vcpkg_prettify_command)
function(vcpkg_execute_build_process)
    cmake_parse_arguments(_ebp "" "WORKING_DIRECTORY;LOGNAME" "COMMAND;NO_PARALLEL_COMMAND" ${ARGN})

    set(LOG_OUT "${CURRENT_BUILDTREES_DIR}/${_ebp_LOGNAME}-out.log")
    set(LOG_ERR "${CURRENT_BUILDTREES_DIR}/${_ebp_LOGNAME}-err.log")

    execute_process(
        COMMAND ${_ebp_COMMAND}
        WORKING_DIRECTORY ${_ebp_WORKING_DIRECTORY}
        OUTPUT_FILE ${LOG_OUT}
        ERROR_FILE ${LOG_ERR}
        RESULT_VARIABLE error_code
    )

    if(error_code)
        file(READ ${LOG_OUT} out_contents)
        file(READ ${LOG_ERR} err_contents)

        if(out_contents)
            list(APPEND LOGS ${LOG_OUT})
        endif()
        if(err_contents)
            list(APPEND LOGS ${LOG_ERR})
        endif()

        if(out_contents MATCHES "LINK : fatal error LNK1102:" OR out_contents MATCHES " fatal error C1060: "
           OR err_contents MATCHES "LINK : fatal error LNK1102:" OR err_contents MATCHES " fatal error C1060: "
           OR out_contents MATCHES "LINK : fatal error LNK1318: Unexpected PDB error; ACCESS_DENIED"
           OR out_contents MATCHES "LINK : fatal error LNK1104:"
           OR out_contents MATCHES "LINK : fatal error LNK1201:"
            # The linker ran out of memory during execution. We will try continuing once more, with parallelism disabled.
           OR err_contents MATCHES "Cannot create parent directory" OR err_contents MATCHES "Cannot write file"
            # Multiple threads using the same directory at the same time cause conflicts, will try again.
           OR err_contents MATCHES "Can't open"
            # Multiple threads caused the wrong order of creating folders and creating files in folders
           )
            message(STATUS "Restarting Build without parallelism because memory exceeded")
            set(LOG_OUT "${CURRENT_BUILDTREES_DIR}/${_ebp_LOGNAME}-out-1.log")
            set(LOG_ERR "${CURRENT_BUILDTREES_DIR}/${_ebp_LOGNAME}-err-1.log")

            if(_ebp_NO_PARALLEL_COMMAND)
                execute_process(
                    COMMAND ${_ebp_NO_PARALLEL_COMMAND}
                    WORKING_DIRECTORY ${_ebp_WORKING_DIRECTORY}
                    OUTPUT_FILE ${LOG_OUT}
                    ERROR_FILE ${LOG_ERR}
                    RESULT_VARIABLE error_code
                )
            else()
                execute_process(
                    COMMAND ${_ebp_COMMAND}
                    WORKING_DIRECTORY ${_ebp_WORKING_DIRECTORY}
                    OUTPUT_FILE ${LOG_OUT}
                    ERROR_FILE ${LOG_ERR}
                    RESULT_VARIABLE error_code
                )
            endif()

            if(error_code)
                file(READ ${LOG_OUT} out_contents)
                file(READ ${LOG_ERR} err_contents)

                if(out_contents)
                    list(APPEND LOGS ${LOG_OUT})
                endif()
                if(err_contents)
                    list(APPEND LOGS ${LOG_ERR})
                endif()
            endif()
        elseif(out_contents MATCHES "mt : general error c101008d: " OR out_contents MATCHES "mt.exe : general error c101008d: ")
            # Antivirus workaround - occasionally files are locked and cause mt.exe to fail
            message(STATUS "mt.exe has failed. This may be the result of anti-virus. Disabling anti-virus on the buildtree folder may improve build speed")
            set(ITERATION 0)
            while (ITERATION LESS 3 AND (out_contents MATCHES "mt : general error c101008d: " OR out_contents MATCHES "mt.exe : general error c101008d: "))
                MATH(EXPR ITERATION "${ITERATION}+1")
                message(STATUS "Restarting Build ${TARGET_TRIPLET}-${SHORT_BUILDTYPE} because of mt.exe file locking issue. Iteration: ${ITERATION}")
                execute_process(
                    COMMAND ${_ebp_COMMAND}
                    OUTPUT_FILE "${LOGPREFIX}-out-${ITERATION}.log"
                    ERROR_FILE "${LOGPREFIX}-err-${ITERATION}.log"
                    RESULT_VARIABLE error_code
                    WORKING_DIRECTORY ${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-${SHORT_BUILDTYPE})

                if(error_code)
                    file(READ "${LOGPREFIX}-out-${ITERATION}.log" out_contents)
                    file(READ "${LOGPREFIX}-err-${ITERATION}.log" err_contents)

                    if(out_contents)
                        list(APPEND LOGS "${LOGPREFIX}-out-${ITERATION}.log")
                    endif()
                    if(err_contents)
                        list(APPEND LOGS "${LOGPREFIX}-err-${ITERATION}.log")
                    endif()
                else()
                    break()
                endif()
            endwhile()
        endif()

        if(error_code)
            set(STRINGIFIED_LOGS)
            foreach(LOG ${LOGS})
                file(TO_NATIVE_PATH "${LOG}" NATIVE_LOG)
                list(APPEND STRINGIFIED_LOGS "    ${NATIVE_LOG}\n")
            endforeach()
            vcpkg_prettify_command(_ebp_COMMAND _ebp_COMMAND_PRETTY)
            message(FATAL_ERROR
                "  Command failed: ${_ebp_COMMAND_PRETTY}\n"
                "  Working Directory: ${_ebp_WORKING_DIRECTORY}\n"
                "  See logs for more information:\n"
                ${STRINGIFIED_LOGS})
        endif(error_code)
    endif(error_code)
endfunction(vcpkg_execute_build_process)