├── CMakeLists.txt ├── LICENSE ├── README ├── cleanup.sh ├── cmake └── FindCXX11.cmake ├── config.h.cmake.in ├── debian ├── changelog ├── compat ├── control ├── copyright ├── rules └── source │ └── format ├── package.sh └── src ├── CMakeLists.txt ├── wclang.cbp ├── wclang.cpp ├── wclang.h ├── wclang_time.cpp └── wclang_time.h /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.5) 2 | 3 | if (NOT DEFINED CMAKE_BUILD_TYPE) 4 | set (CMAKE_BUILD_TYPE Release CACHE STRING "Build type") 5 | endif () 6 | 7 | project (wclang) 8 | 9 | 10 | include (CheckIncludeFiles) 11 | check_include_files (sys/types.h HAVE_SYS_TYPES_H) 12 | check_include_files (sys/stat.h HAVE_SYS_STAT_H) 13 | check_include_files (string.h HAVE_STRING_H) 14 | check_include_files (strings.h HAVE_STRINGS_H) 15 | check_include_files (unistd.h HAVE_UNISTD_H) 16 | check_include_files (inttypes.h HAVE_INTTYPES_H) 17 | check_include_files (memory.h HAVE_MEMORY_H) 18 | check_include_files (stdint.h HAVE_STDINT_H) 19 | check_include_files (stdlib.h HAVE_STDLIB_H) 20 | 21 | 22 | include (CheckFunctionExists) 23 | check_function_exists (getpid HAVE_GETPID) 24 | check_function_exists (unsetenv HAVE_UNSETENV) 25 | check_function_exists (strrchr HAVE_STRRCHR) 26 | check_function_exists (strchr HAVE_STRCHR) 27 | check_function_exists (strdup HAVE_STRDUP) 28 | check_function_exists (fork HAVE_FORK) 29 | check_function_exists (execvp HAVE_EXECVP) 30 | check_function_exists (getenv HAVE_GETENV) 31 | check_function_exists (setenv HAVE_SETENV) 32 | check_function_exists (gettimeofday HAVE_GETTIMEOFDAY) 33 | check_function_exists (opendir HAVE_OPENDIR) 34 | 35 | 36 | include (CheckCXXCompilerFlag) 37 | set (WARNING_FLAGS "-pedantic -Wall -Wextra -Wno-unused-parameter") 38 | check_cxx_compiler_flag("${WARNING_FLAGS}" _SUPPORT_WARNING_FLAGS) 39 | if (_SUPPORT_WARNING_FLAGS) 40 | set (CMAKE_CXX_FLAGS "${WARNING_FLAGS} ${CMAKE_CXX_FLAGS}") 41 | endif () 42 | 43 | list (APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) 44 | find_package (CXX11 REQUIRED) 45 | set (HAVE_CXX11 ${CXX11_FOUND}) 46 | set (CMAKE_CXX_FLAGS "${CXX11_FLAGS} ${CMAKE_CXX_FLAGS}") 47 | 48 | include (CheckCXXSourceCompiles) 49 | check_cxx_source_compiles ("#include 50 | int main() { 51 | std::chrono::steady_clock::now(); 52 | }" HAVE_STD_CHRONO) 53 | 54 | 55 | set (PACKAGE_NAME ${PROJECT_NAME}) 56 | set (PACKAGE_BUGREPORT t.poechtrager@gmail.com) 57 | set (PACKAGE_VERSION 0.6) 58 | set (VERSION "${PROJECT_NAME} 0.6") 59 | 60 | 61 | find_program (CLANG_C_COMPILER NAMES clang) 62 | if (CLANG_C_COMPILER) 63 | message (STATUS "Found clang: ${CLANG_C_COMPILER}") 64 | else () 65 | message (SEND_ERROR "clang was not found") 66 | endif () 67 | execute_process ( COMMAND ${CLANG_C_COMPILER} --version 68 | OUTPUT_VARIABLE CLANG_VERSION 69 | OUTPUT_STRIP_TRAILING_WHITESPACE 70 | ) 71 | string (REGEX REPLACE ".*version ([0-9\\.]+).*" 72 | "\\1" CLANG_VERSION 73 | "${CLANG_VERSION}") 74 | if (CLANG_VERSION VERSION_GREATER 3.0) 75 | set (CLANG_TARGET_OPT_FLAG -target) 76 | else () 77 | set (CLANG_TARGET_OPT_FLAG -ccc-host-triple) 78 | endif () 79 | add_definitions (-DCLANG_TARGET_OPT=\"${CLANG_TARGET_OPT_FLAG}\") 80 | get_filename_component(CLANG_PATH ${CLANG_C_COMPILER} PATH) 81 | 82 | set (TRIPLETS i686-w64-mingw32 x86_64-w64-mingw32) 83 | list (APPEND TRIPLETS i686-w64-mingw32.static x86_64-w64-mingw32.static) 84 | list (APPEND TRIPLETS i686-w64-mingw32.shared x86_64-w64-mingw32.shared) 85 | list (APPEND TRIPLETS i486-mingw32 i586-mingw32) 86 | list (APPEND TRIPLETS i586-mingw32msvc amd64-mingw32msvc) 87 | 88 | set (VALID_TRIPLETS) 89 | set (MINGW_PATHS_DEF) 90 | foreach (TRIPLET ${TRIPLETS}) 91 | unset (MINGW_C_COMPILER CACHE) 92 | find_program (MINGW_C_COMPILER NAMES ${TRIPLET}-gcc) 93 | if (MINGW_C_COMPILER) 94 | get_filename_component (MINGW_C_COMPILER_REALPATH ${MINGW_C_COMPILER} REALPATH) 95 | get_filename_component (MINGW_PATH ${MINGW_C_COMPILER_REALPATH} PATH) 96 | if (MINGW_PATHS_DEF) 97 | set (MINGW_PATHS_DEF "${MINGW_PATHS_DEF}:${MINGW_PATH}") 98 | else () 99 | set (MINGW_PATHS_DEF ${MINGW_PATH}) 100 | endif () 101 | message (STATUS "Found mingw-gcc: ${MINGW_C_COMPILER_REALPATH}") 102 | list (APPEND VALID_TRIPLETS ${TRIPLET}) 103 | endif () 104 | endforeach () 105 | if (NOT VALID_TRIPLETS) 106 | message (SEND_ERROR "mingw-gcc was not found") 107 | endif () 108 | add_definitions(-DMINGW_PATH=\"${MINGW_PATHS_DEF}\") 109 | 110 | 111 | configure_file (${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) 112 | include_directories (${CMAKE_CURRENT_BINARY_DIR}) 113 | 114 | add_subdirectory (src) 115 | 116 | 117 | 118 | set (CPACK_SOURCE_GENERATOR "TGZ;TBZ2" ) 119 | set (CPACK_SOURCE_IGNORE_FILES "/.git;/build;.*~;${CPACK_SOURCE_IGNORE_FILES}") 120 | set (CPACK_SOURCE_PACKAGE_FILE_NAME "${PACKAGE_NAME}-${PACKAGE_VERSION}") 121 | include (CPack) 122 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Wclang is a tool which helps you to cross compile source code easily with clang on Linux/Unix for Windows. 2 | Wclang is basically a wrapper for clang, which allows you to directly target Windows. 3 | Wclang detects the target and headers automatically and adds them to the clang invocation command. 4 | 5 | After the installation you will have "-clang", "-clang++" available as "compiler". 6 | 7 | PREREQUISITES: 8 | 9 | A C++11 compiler for compiling the wrapper (g++ 4.6+, clang) 10 | clang 11 | mingw-w64 with its headers and libs 12 | cmake 13 | 14 | INSTALLATION: 15 | 16 | cmake -DCMAKE_INSTALL_PREFIX=_prefix_ . 17 | make 18 | make install 19 | 20 | EXAMPLES: 21 | 22 | i686-w64-mingw32-clang++ hello-world.cpp -o hello-world.exe && wine hello-world 23 | CC=i686-w64-mingw32-clang ./configure --host=i686-w64-mingw32 24 | 25 | x86_64-w64-mingw32-clang++ hello-world.cpp -o hello-world.exe && wine hello-world 26 | CC=x86_64-w64-mingw32-clang ./configure --host=x86_64-w64-mingw32 27 | 28 | LISTING AVAILABLE PARAMETERS: 29 | i686-w64-clang -wc-help 30 | 31 | LIMITATIONS: 32 | C++ exceptions do not work with clang<3.7, and in 3.7 just for 64-bit, clang>=6.0 added support for 32-bit. 33 | 34 | KNOWN TO WORK ON: 35 | 36 | Linux: Ubuntu, Debian (Wheezy*), Mint, Arch, Fedora and openSUSE. 37 | Other distributions may work as well, but have not been tested. 38 | Windows: Cygwin. 39 | 40 | * Wheezy: important: clang-3.0 coming with wheezy is too old 41 | to compile the wrapper, so use g++ or get a newer clang 42 | from e.g.: http://llvm.org/apt. 43 | -------------------------------------------------------------------------------- /cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | git clean -fdx 1>/dev/null -------------------------------------------------------------------------------- /cmake/FindCXX11.cmake: -------------------------------------------------------------------------------- 1 | # - Finds if the compiler has C++11 support 2 | # This module can be used to detect compiler flags for using C++11, and checks 3 | # a small subset of the language. 4 | # 5 | # The following variables are set: 6 | # CXX11_FLAGS - flags to add to the CXX compiler for C++11 support 7 | # CXX11_FOUND - true if the compiler supports C++11 8 | # 9 | # TODO: When compilers starts implementing the whole C++11, check the full set 10 | 11 | include(CheckCXXSourceCompiles) 12 | include(FindPackageHandleStandardArgs) 13 | 14 | set(CXX11_FLAG_CANDIDATES 15 | # cygwin 16 | "-std=gnu++0x" 17 | #Gnu and Intel Linux 18 | "-std=c++0x" 19 | #Microsoft Visual Studio, and everything that automatically accepts C++11 20 | " " 21 | #Intel windows 22 | "/Qstd=c++0x" 23 | ) 24 | 25 | set(CXX11_TEST_SOURCE 26 | " 27 | class Matrix 28 | { 29 | public: 30 | Matrix(int a, int b, int c, int d) 31 | : data {a, b, c, d} 32 | {} 33 | 34 | private: 35 | int data[4]; 36 | }; 37 | 38 | int main() 39 | { 40 | int n[] {4,7,6,1,2}; 41 | for (auto i : n) 42 | Matrix mat (3,5,1,2); 43 | return 0; 44 | } 45 | ") 46 | 47 | foreach(FLAG ${CXX11_FLAG_CANDIDATES}) 48 | set(SAFE_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") 49 | set(CMAKE_REQUIRED_FLAGS "${FLAG}") 50 | unset(CXX11_FLAG_DETECTED CACHE) 51 | message(STATUS "Try C++11 flag = [${FLAG}]") 52 | check_cxx_source_compiles("${CXX11_TEST_SOURCE}" CXX11_FLAG_DETECTED) 53 | set(CMAKE_REQUIRED_FLAGS "${SAFE_CMAKE_REQUIRED_FLAGS}") 54 | if(CXX11_FLAG_DETECTED) 55 | set(CXX11_FLAGS_INTERNAL "${FLAG}") 56 | break() 57 | endif(CXX11_FLAG_DETECTED) 58 | endforeach(FLAG ${CXX11_FLAG_CANDIDATES}) 59 | 60 | set(CXX11_FLAGS "${CXX11_FLAGS_INTERNAL}") 61 | 62 | find_package_handle_standard_args(CXX11 DEFAULT_MSG CXX11_FLAGS) 63 | mark_as_advanced(CXX11_FLAGS) -------------------------------------------------------------------------------- /config.h.cmake.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* define if the compiler supports basic C++11 syntax */ 4 | #cmakedefine HAVE_CXX11 5 | 6 | /* Define to 1 if you have the `execvp' function. */ 7 | #cmakedefine HAVE_EXECVP 8 | 9 | /* Define to 1 if you have the `fork' function. */ 10 | #cmakedefine HAVE_FORK 11 | 12 | /* Define to 1 if you have the `getenv' function. */ 13 | #cmakedefine HAVE_GETENV 14 | 15 | /* Define to 1 if you have the `getpid' function. */ 16 | #cmakedefine HAVE_GETPID 17 | 18 | /* Define to 1 if you have the `gettimeofday' function. */ 19 | #cmakedefine HAVE_GETTIMEOFDAY 20 | 21 | /* Define to 1 if you have the header file. */ 22 | #cmakedefine HAVE_INTTYPES_H 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #cmakedefine HAVE_MEMORY_H 26 | 27 | /* Define to 1 if you have the `opendir' function. */ 28 | #cmakedefine HAVE_OPENDIR 29 | 30 | /* Define to 1 if you have the `setenv' function. */ 31 | #cmakedefine HAVE_SETENV 32 | 33 | /* Define to 1 if you have the header file. */ 34 | #cmakedefine HAVE_STDINT_H 35 | 36 | /* Define to 1 if you have the header file. */ 37 | #cmakedefine HAVE_STDLIB_H 38 | 39 | /* define if std::chrono is supported */ 40 | #cmakedefine HAVE_STD_CHRONO 41 | 42 | /* Define to 1 if you have the `strchr' function. */ 43 | #cmakedefine HAVE_STRCHR 44 | 45 | /* Define to 1 if you have the `strdup' function. */ 46 | #cmakedefine HAVE_STRDUP 47 | 48 | /* Define to 1 if you have the header file. */ 49 | #cmakedefine HAVE_STRINGS_H 50 | 51 | /* Define to 1 if you have the header file. */ 52 | #cmakedefine HAVE_STRING_H 53 | 54 | /* Define to 1 if you have the `strrchr' function. */ 55 | #cmakedefine HAVE_STRRCHR 56 | 57 | /* Define to 1 if you have the header file. */ 58 | #cmakedefine HAVE_SYS_STAT_H 59 | 60 | /* Define to 1 if you have the header file. */ 61 | #cmakedefine HAVE_SYS_TYPES_H 62 | 63 | /* Define to 1 if you have the header file. */ 64 | #cmakedefine HAVE_UNISTD_H 65 | 66 | /* Define to 1 if the system has the type `_Bool'. */ 67 | #cmakedefine HAVE__BOOL 68 | 69 | /* Name of package */ 70 | #cmakedefine PACKAGE "@PACKAGE@" 71 | 72 | /* Define to the address where bug reports for this package should be sent. */ 73 | #cmakedefine PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" 74 | 75 | /* Define to the full name of this package. */ 76 | #define PACKAGE_NAME "@PACKAGE_NAME@" 77 | 78 | /* Define to the full name and version of this package. */ 79 | #cmakedefine PACKAGE_STRING "@PACKAGE_STRING@" 80 | 81 | /* Define to the one symbol short name of this package. */ 82 | #cmakedefine PACKAGE_TARNAME "@PACKAGE_TARNAME@" 83 | 84 | /* Define to the home page for this package. */ 85 | #cmakedefine PACKAGE_URL "@PACKAGE_URL@" 86 | 87 | /* Define to the version of this package. */ 88 | #cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@" 89 | 90 | /* Define to 1 if you have the ANSI C header files. */ 91 | #cmakedefine STDC_HEADERS 92 | 93 | /* Version number of package */ 94 | #cmakedefine VERSION "@VERSION@" 95 | 96 | /* Define to `unsigned int' if does not define. */ 97 | #cmakedefine size_t 98 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | wclang (1.0.0-1) unstable; urgency=low 2 | 3 | * Initial release 4 | 5 | -- Mateusz Mikuła Tue, 19 Sep 2017 00:10:54 +0200 6 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: wclang 2 | Section: devel 3 | Priority: optional 4 | Maintainer: Mateusz Mikuła 5 | Build-Depends: debhelper (>= 9), cmake, clang, mingw-w64 6 | Standards-Version: 3.9.8 7 | Homepage: https://github.com/tpoechtrager/wclang 8 | Vcs-Git: https://github.com/tpoechtrager/wclang.git 9 | Vcs-Browser: https://github.com/tpoechtrager/wclang.git 10 | 11 | Package: wclang 12 | Architecture: any 13 | Depends: ${shlibs:Depends}, ${misc:Depends}, clang, mingw-w64 14 | Description: Cross compile source code easily for Windows with clang on Linux/Unix 15 | Wclang is a tool which helps you to cross compile source code easily with clang on Linux/Unix for Windows. 16 | Wclang is basically a wrapper for clang, which allows you to directly target Windows. 17 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: wclang 3 | Source: 4 | 5 | Files: * 6 | Copyright: 2013-2017 Thomas Poechtrager 7 | License: GPL-2.0 8 | See /usr/share/common-licenses/GPL-2 for a full copy of the license. 9 | 10 | # If you want to use GPL v2 or later for the /debian/* files use 11 | # the following clauses, or change it to suit. Delete these two lines 12 | Files: debian/* 13 | Copyright: 2017 Mateusz Mikuła 14 | License: GPL-2+ 15 | This package is free software; you can redistribute it and/or modify 16 | it under the terms of the GNU General Public License as published by 17 | the Free Software Foundation; either version 2 of the License, or 18 | (at your option) any later version. 19 | . 20 | This package is distributed in the hope that it will be useful, 21 | but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | GNU General Public License for more details. 24 | . 25 | You should have received a copy of the GNU General Public License 26 | along with this program. If not, see 27 | . 28 | On Debian systems, the complete text of the GNU General 29 | Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". 30 | 31 | # Please also look if there are files or directories which have a 32 | # different copyright/license attached and list them here. 33 | # Please avoid picking licenses with terms that are more restrictive than the 34 | # packaged work, as it may make Debian's contributions unacceptable upstream. 35 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | %: 3 | dh $@ 4 | 5 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /package.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | dir=`pwd` 4 | packagetmp=`mktemp -d` 5 | cp -r . $packagetmp || exit $? 6 | pushd $packagetmp >/dev/null 7 | ./cleanup.sh 2>/dev/null 8 | rm -rf .git 2>/dev/null 9 | rm wclang.tar.xz 2>/dev/null 10 | XZ_OPT=-9 tar cJf $dir/wclang.tar.xz * || exit $? 11 | popd >/dev/null 12 | rm -rf $packagetmp || exit $? 13 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(wclang wclang.cpp wclang_time.cpp) 2 | install(TARGETS wclang DESTINATION bin) 3 | 4 | option(SYMLINK_ALL_TRIPLETS "symlink all triplets" OFF) 5 | set(SYMLINK_TRIPLETS ${VALID_TRIPLETS}) 6 | if(SYMLINK_ALL_TRIPLETS) 7 | set(SYMLINK_TRIPLETS ${TRIPLETS}) 8 | endif () 9 | 10 | list (INSERT SHORTCUTS 0 w32-clang w32-clang++ w64-clang w64-clang++) 11 | 12 | foreach (SHORTCUT ${SHORTCUTS}) 13 | install(CODE "set(FINAL_DIR ${CMAKE_INSTALL_PREFIX}) 14 | message(STATUS \"Symlinking: \${FINAL_DIR}/bin/${SHORTCUT} -> wclang\") 15 | execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink wclang ${SHORTCUT} WORKING_DIRECTORY \${FINAL_DIR}/bin)") 16 | endforeach () 17 | 18 | foreach (TRIPLET ${SYMLINK_TRIPLETS}) 19 | install(CODE "set(FINAL_DIR ${CMAKE_INSTALL_PREFIX}) 20 | if(NOT \"\$ENV{DESTDIR}\" STREQUAL \"\") 21 | set(FINAL_DIR \$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}) 22 | endif() 23 | message(STATUS \"Symlinking: \${FINAL_DIR}/bin/${TRIPLET}-clang -> wclang\") 24 | execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink wclang ${TRIPLET}-clang WORKING_DIRECTORY \${FINAL_DIR}/bin) 25 | message(STATUS \"Symlinking: \${FINAL_DIR}/bin/${TRIPLET}-clang++ -> wclang\") 26 | execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink wclang ${TRIPLET}-clang++ WORKING_DIRECTORY \${FINAL_DIR}/bin)") 27 | endforeach () 28 | 29 | foreach (TRIPLET ${VALID_TRIPLETS}) 30 | install(CODE "unset (MINGW_C_COMPILER CACHE) 31 | find_program (MINGW_C_COMPILER NAMES ${TRIPLET}-gcc) 32 | if (MINGW_C_COMPILER) 33 | get_filename_component (MINGW_C_COMPILER_REALPATH ${MINGW_C_COMPILER} REALPATH) 34 | get_filename_component (MINGW_PATH ${MINGW_C_COMPILER_REALPATH} PATH) 35 | if (NOT EXISTS ${CLANG_PATH}/${TRIPLET}-gcc) 36 | message(STATUS \"Symlinking: ${MINGW_PATH}/${TRIPLET}-* -> ${CLANG_PATH}\") 37 | execute_process(COMMAND sh -c \"ln -sf ${MINGW_PATH}/${TRIPLET}-* ${CLANG_PATH}/\") 38 | endif () 39 | endif ()") 40 | endforeach () 41 | -------------------------------------------------------------------------------- /src/wclang.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 59 | 60 | -------------------------------------------------------------------------------- /src/wclang.cpp: -------------------------------------------------------------------------------- 1 | /*********************************************************************** 2 | * wclang * 3 | * Copyright (C) 2013-2019 Thomas Poechtrager * 4 | * t.poechtrager@gmail.com * 5 | * * 6 | * This program is free software; you can redistribute it and/or * 7 | * modify it under the terms of the GNU General Public License * 8 | * as published by the Free Software Foundation; either version 2 * 9 | * of the License, or (at your option) any later version. * 10 | * * 11 | * This program is distributed in the hope that it will be useful, * 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 14 | * GNU General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU General Public License * 17 | * along with this program; if not, write to the Free Software * 18 | * Foundation, Inc., * 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 20 | ***********************************************************************/ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include "wclang.h" 37 | #include "wclang_time.h" 38 | 39 | /* 40 | * Supported targets 41 | */ 42 | 43 | enum { 44 | TARGET_WIN32 = 0, 45 | TARGET_WIN64 46 | }; 47 | 48 | static constexpr const char* TARGET32[] = { 49 | "i686-w64-mingw32", 50 | "i686-w64-mingw32.static", /* MXE */ 51 | "i686-w64-mingw32.shared", /* MXE */ 52 | "i686-pc-mingw32", 53 | "i586-mingw32", 54 | "i586-mingw32msvc", 55 | "i486-mingw32" 56 | }; 57 | 58 | static constexpr const char* TARGET64[] = { 59 | "x86_64-w64-mingw32", 60 | "x86_64-w64-mingw32.static", /* MXE */ 61 | "x86_64-w64-mingw32.shared", /* MXE */ 62 | "amd64-mingw32msvc" 63 | }; 64 | 65 | /* 66 | * Additional C/C++ flags 67 | */ 68 | static constexpr char CXXFLAGS[] = ""; 69 | static constexpr char CFLAGS[] = ""; 70 | 71 | static constexpr const char* ENVVARS[] = { 72 | "AR", "AS", "CPP", "DLLTOOL", "DLLWRAP", 73 | "ELFEDIT","GCOV", "GNAT", "LD", "NM", 74 | "OBJCOPY", "OBJDUMP", "RANLIB", "READELF", 75 | "SIZE", "STRINGS", "STRIP", "WINDMC", "WINDRES" 76 | }; 77 | 78 | static constexpr char COMMANDPREFIX[] = "-wc-"; 79 | 80 | #ifndef NO_SYS_PATH 81 | /* 82 | * Paths where we should look for mingw C++ headers 83 | */ 84 | 85 | static constexpr const char* CXXINCLUDEBASE[] = { 86 | "/usr", 87 | "/usr/lib/gcc", 88 | "/usr/local/include/c++", 89 | "/usr/include/c++", 90 | "/opt" 91 | }; 92 | 93 | /* 94 | * Paths where we should look for mingw C headers 95 | */ 96 | 97 | static constexpr const char* STDINCLUDEBASE[] = { 98 | "/usr", 99 | "/usr/local", 100 | "/opt" 101 | }; 102 | #endif 103 | 104 | static bool findcxxheaders(const char *target, commandargs &cmdargs) 105 | { 106 | std::string root; 107 | std::string cxxheaders; 108 | std::string mingwheaders; 109 | auto &mv = cmdargs.mingwversion; 110 | auto &cxxpaths = cmdargs.cxxpaths; 111 | const auto &stdpaths = cmdargs.stdpaths; 112 | static const char *_target = target; 113 | 114 | auto checkmingwheaders = [](const char *dir, const char *file) 115 | { 116 | static struct stat st; 117 | static std::stringstream d; 118 | 119 | clear(d); 120 | d << dir << file << "/" << _target; 121 | 122 | return !stat(d.str().c_str(), &st); 123 | }; 124 | 125 | auto checkheaderdir = [](const std::string &cxxheaderdir) 126 | { 127 | static std::string file; 128 | static struct stat st; 129 | 130 | file = cxxheaderdir; 131 | file += "/"; 132 | file += "iostream"; 133 | 134 | return !stat(file.c_str(), &st); 135 | }; 136 | 137 | auto addheaderdir = [&](const std::string &cxxheaderdir, bool mingw) 138 | { 139 | static std::string mingwheaderdir; 140 | cxxpaths.push_back(cxxheaderdir); 141 | 142 | if (mingw) 143 | { 144 | mingwheaderdir = cxxheaderdir; 145 | mingwheaderdir += "/"; 146 | mingwheaderdir += target; 147 | 148 | cxxpaths.push_back(mingwheaderdir); 149 | } 150 | }; 151 | 152 | auto findheaders = [&]() 153 | { 154 | for (const auto &stddir : stdpaths) 155 | { 156 | /* 157 | * a: stddir / c++ 158 | * b: a / xxxx-w64-mingw32 159 | */ 160 | 161 | cxxheaders = stddir; 162 | cxxheaders += "/c++"; 163 | cxxheaders += "/"; 164 | 165 | if (checkheaderdir(cxxheaders)) 166 | { 167 | addheaderdir(cxxheaders, true); 168 | return true; 169 | } 170 | 171 | /* 172 | * a: stddir / c++ / 173 | * b: a / xxxx-w64-mingw32 174 | */ 175 | 176 | mv = findlatestcompilerversion(cxxheaders.c_str()); 177 | 178 | if (!mv.num()) 179 | continue; 180 | 181 | cxxheaders += mv.s; 182 | 183 | if (checkheaderdir(cxxheaders)) 184 | { 185 | addheaderdir(cxxheaders, true); 186 | return true; 187 | } 188 | } 189 | 190 | #ifndef NO_SYS_PATH 191 | for (const char *cxxinclude : CXXINCLUDEBASE) 192 | { 193 | /* 194 | * a: root / cxxinclude / 195 | * b: a / xxxx-w64-mingw32 196 | */ 197 | 198 | cxxheaders = root; 199 | cxxheaders += cxxinclude; 200 | cxxheaders += "/"; 201 | 202 | mv = findlatestcompilerversion(cxxheaders.c_str(), 203 | checkmingwheaders); 204 | 205 | if (!mv.num()) 206 | continue; 207 | 208 | cxxheaders += mv.s; 209 | 210 | if (checkheaderdir(cxxheaders)) 211 | { 212 | addheaderdir(cxxheaders, true); 213 | return true; 214 | } 215 | } 216 | 217 | for (const char *cxxinclude : CXXINCLUDEBASE) 218 | { 219 | /* 220 | * a: root / cxxinclude / / / include / c++ 221 | * b: root / cxxinclude / / / xxxx-w64-mingw32 222 | */ 223 | 224 | cxxheaders = root; 225 | cxxheaders += cxxinclude; 226 | cxxheaders += "/"; 227 | cxxheaders += target; 228 | cxxheaders += "/"; 229 | 230 | mv = findlatestcompilerversion(cxxheaders.c_str(), 231 | checkmingwheaders); 232 | 233 | if (!mv.num()) 234 | continue; 235 | 236 | mingwheaders = cxxheaders; 237 | 238 | cxxheaders += mv.s; 239 | cxxheaders += "/include/c++"; 240 | 241 | if (checkheaderdir(cxxheaders)) 242 | { 243 | addheaderdir(cxxheaders, false); 244 | addheaderdir(mingwheaders, false); 245 | return true; 246 | } 247 | } 248 | 249 | for (const char *cxxinclude : CXXINCLUDEBASE) 250 | { 251 | /* 252 | * a: root / cxxinclude / / / include / c++ 253 | * b: a / xxxx-w64-mingw32 254 | */ 255 | 256 | cxxheaders = root; 257 | cxxheaders += cxxinclude; 258 | cxxheaders += "/"; 259 | cxxheaders += target; 260 | cxxheaders += "/"; 261 | 262 | mv = findlatestcompilerversion(cxxheaders.c_str()); 263 | 264 | if (!mv.num()) 265 | continue; 266 | 267 | cxxheaders += mv.s; 268 | cxxheaders += "/include/c++"; 269 | 270 | if (!checkmingwheaders(cxxheaders.c_str(), "")) 271 | continue; 272 | 273 | if (checkheaderdir(cxxheaders)) 274 | { 275 | addheaderdir(cxxheaders, true); 276 | return true; 277 | } 278 | } 279 | #endif 280 | 281 | return false; 282 | }; 283 | 284 | root = stdpaths[0] + "/../../.."; 285 | if (findheaders()) return true; 286 | 287 | root.clear(); 288 | return findheaders(); 289 | } 290 | 291 | static bool findintrinheaders(commandargs &cmdargs, const std::string &clangbindir) 292 | { 293 | static std::stringstream dir; 294 | static compilerver *clangversion; 295 | static std::string pathtmp; 296 | 297 | clangversion = &cmdargs.clangversion; 298 | string_vector &intrinpaths = cmdargs.intrinpaths; 299 | 300 | clear(dir); 301 | *clangversion = compilerver(); 302 | pathtmp.clear(); 303 | 304 | auto trydir = [&]() -> bool 305 | { 306 | listfiles(dir.str().c_str(), nullptr, [](const char *, const char *file) 307 | { 308 | if (file[0] != '.' && isdirectory(file, dir.str().c_str())) 309 | { 310 | compilerver cv = parsecompilerversion(file); 311 | 312 | if (cv != compilerver()) 313 | { 314 | static std::stringstream tmp; 315 | clear(tmp); 316 | 317 | auto checkdir = [&](std::stringstream &dir) 318 | { 319 | static std::string intrindir; 320 | auto &file = dir; 321 | 322 | intrindir = dir.str(); 323 | file << "/xmmintrin.h"; 324 | 325 | if (fileexists(file.str().c_str())) 326 | { 327 | if (cv > *clangversion) 328 | { 329 | *clangversion = cv; 330 | pathtmp.swap(intrindir); 331 | } 332 | return true; 333 | } 334 | 335 | return false; 336 | }; 337 | 338 | tmp << dir.str() << "/" << file << "/include"; 339 | 340 | if (!checkdir(tmp)) 341 | { 342 | clear(tmp); 343 | tmp << dir.str() << "/" << file; 344 | checkdir(tmp); 345 | } 346 | } 347 | return true; 348 | } 349 | return true; 350 | }); 351 | return *clangversion != compilerver(); 352 | }; 353 | 354 | #define TRYDIR(basedir, subdir) \ 355 | do \ 356 | { \ 357 | dir << basedir << subdir; \ 358 | if (trydir()) \ 359 | { \ 360 | intrinpaths.push_back(pathtmp); \ 361 | return true; \ 362 | } \ 363 | clear(dir); \ 364 | } while (0) 365 | 366 | #define TRYDIR2(libdir) TRYDIR(clangbindir, libdir) 367 | #define TRYDIR3(libdir) TRYDIR(std::string(), libdir) 368 | 369 | #ifdef __CYGWIN__ 370 | #ifdef __x86_64__ 371 | TRYDIR2("/../lib/clang/x86_64-pc-cygwin"); 372 | #else 373 | TRYDIR2("/../lib/clang/i686-pc-cygwin"); 374 | #endif 375 | #endif 376 | 377 | TRYDIR2("/../lib/clang"); 378 | 379 | #ifdef __linux__ 380 | #ifdef __x86_64__ 381 | // opensuse uses lib64 instead of lib on x86_64 382 | TRYDIR2("/../lib64/clang"); 383 | #elif __i386__ 384 | TRYDIR2("/../lib32/clang"); 385 | #endif 386 | #endif 387 | 388 | #ifdef __APPLE__ 389 | constexpr const char *OSXIntrinDirs[] = 390 | { 391 | "/Library/Developer/CommandLineTools/usr/lib/clang", 392 | "/Applications/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang" 393 | }; 394 | 395 | for (auto intrindir : OSXIntrinDirs) TRYDIR3(intrindir); 396 | #endif 397 | 398 | TRYDIR2("/../include/clang"); 399 | TRYDIR2("/usr/include/clang"); 400 | 401 | return false; 402 | #undef TRYDIR 403 | #undef TRYDIR2 404 | #undef TRYDIR3 405 | } 406 | 407 | static bool findstdheader(const char *target, commandargs &cmdargs) 408 | { 409 | std::string dir; 410 | struct stat st; 411 | auto &stdpaths = cmdargs.stdpaths; 412 | const char *mingwpath = getenv("MINGW_PATH"); 413 | 414 | auto checkdir = [&](const char *stdinclude) -> bool 415 | { 416 | auto trydir = [&](const std::string &dir) -> bool 417 | { 418 | if (!stat(dir.c_str(), &st) && S_ISDIR(st.st_mode)) 419 | { 420 | std::string filecheck = dir + "/stdlib.h"; 421 | 422 | if (stat(filecheck.c_str(), &st)) 423 | return false; 424 | 425 | stdpaths.push_back(dir); 426 | 427 | #ifdef _DEBUG 428 | for (const auto &dir : stdpaths) 429 | std::cout << "found C include dir: " << dir << std::endl; 430 | #endif 431 | 432 | return true; 433 | } 434 | 435 | return false; 436 | }; 437 | 438 | dir = stdinclude; 439 | dir += "/"; 440 | dir += target; 441 | dir += "/include"; 442 | 443 | if (trydir(dir)) 444 | return true; 445 | 446 | dir = stdinclude; 447 | dir += "/"; 448 | dir += target; 449 | dir += "/sys-root/mingw/include"; 450 | 451 | if (trydir(dir)) 452 | return true; 453 | 454 | // MXE 455 | dir = stdinclude; 456 | dir += "/usr/"; 457 | dir += target; 458 | dir += "/include"; 459 | 460 | if (trydir(dir)) 461 | return true; 462 | 463 | return false; 464 | }; 465 | 466 | auto checkpath = [&](const char *p) -> bool 467 | { 468 | std::string path; 469 | 470 | do 471 | { 472 | if (*p == ':') p++; 473 | 474 | while (*p && *p != ':') 475 | path += *p++; 476 | 477 | if (path.find_last_of("/bin") != std::string::npos) 478 | path.resize(path.size()-STRLEN("/bin")); 479 | 480 | if (checkdir(path.c_str())) 481 | return true; 482 | 483 | path.clear(); 484 | } while (*p); 485 | 486 | return false; 487 | }; 488 | 489 | if (mingwpath && *mingwpath) 490 | return checkpath(mingwpath); 491 | 492 | #ifdef MINGW_PATH 493 | if (*MINGW_PATH && checkpath(MINGW_PATH)) 494 | return true; 495 | #endif 496 | 497 | #ifndef NO_SYS_PATH 498 | for (const char *stdinclude : STDINCLUDEBASE) 499 | if (checkdir(stdinclude)) return true; 500 | #endif 501 | 502 | return false; 503 | } 504 | 505 | static const char *findtarget32(commandargs &cmdargs) 506 | { 507 | for (const char *target : TARGET32) 508 | if (findstdheader(target, cmdargs)) return target; 509 | 510 | return nullptr; 511 | } 512 | 513 | static const char *findtarget64(commandargs &cmdargs) 514 | { 515 | for (const char *target : TARGET64) 516 | if (findstdheader(target, cmdargs)) return target; 517 | 518 | return nullptr; 519 | } 520 | 521 | static bool findheaders(commandargs &cmdargs, const std::string &target) 522 | { 523 | return findstdheader(target.c_str(), cmdargs); 524 | } 525 | 526 | static const char *findtriple(const char *name, int &targettype) 527 | { 528 | const char *p = std::strstr(name, "-clang"); 529 | size_t len = p-name; 530 | 531 | if (!p) 532 | return nullptr; 533 | 534 | for (const char *target : TARGET32) 535 | { 536 | if (!std::strncmp(target, name, len) && !target[len]) 537 | { 538 | targettype = TARGET_WIN32; 539 | return target; 540 | } 541 | } 542 | 543 | for (const char *target : TARGET64) 544 | { 545 | if (!std::strncmp(target, name, len) && !target[len]) 546 | { 547 | targettype = TARGET_WIN64; 548 | return target; 549 | } 550 | } 551 | 552 | return nullptr; 553 | } 554 | 555 | void appendexetooutputname(char **cargs) 556 | { 557 | const char *filename; 558 | const char *suffix; 559 | 560 | for (char **arg = cargs; *arg; ++arg) 561 | { 562 | if (!std::strncmp(*arg, "-o", STRLEN("-o"))) 563 | { 564 | if (!(*arg)[2] && (!*++arg || **arg == '-')) 565 | break; 566 | 567 | if (!std::strncmp(*arg, "-o", STRLEN("-o"))) 568 | filename = &(*arg)[2]; 569 | else 570 | filename = *arg; 571 | 572 | suffix = std::strrchr(filename, '.'); 573 | 574 | if (suffix) 575 | { 576 | if (!std::strcmp(suffix, ".exe") || !std::strcmp(suffix, ".dll") || 577 | !std::strcmp(suffix, ".S")) 578 | { 579 | return; 580 | } 581 | } 582 | 583 | for (char **p = arg+1; *p; ++p) 584 | { 585 | if (!std::strcmp(*p, "-c")) 586 | return; 587 | } 588 | 589 | std::cerr << R"(wclang: appending ".exe" to output filename ")" 590 | << filename << R"(")" << std::endl; 591 | 592 | filename = nullptr; 593 | suffix = nullptr; 594 | 595 | const size_t len = std::strlen(*arg)+STRLEN(".exe")+1; 596 | *arg = static_cast(std::realloc(*arg, len)); 597 | 598 | if (!*arg) 599 | { 600 | std::cerr << "out of memory" << std::endl; 601 | std::exit(EXIT_FAILURE); 602 | } 603 | 604 | std::strcat(*arg, ".exe"); 605 | break; 606 | } 607 | else if (!std::strcmp(*arg, "-c")) { 608 | break; 609 | } 610 | } 611 | } 612 | 613 | /* 614 | * Tools 615 | */ 616 | 617 | bool isterminal() 618 | { 619 | static bool first = false; 620 | static bool val; 621 | 622 | if (!first) 623 | { 624 | val = !!isatty(fileno(stderr)); 625 | first = true; 626 | } 627 | 628 | return val; 629 | } 630 | 631 | void concatenvvariable(const char *var, const std::string val, std::string *nval) 632 | { 633 | std::string tmp; 634 | if (!nval) nval = &tmp; 635 | *nval = val; 636 | 637 | if (char *oldval = getenv(var)) 638 | { 639 | *nval += ":"; 640 | *nval += oldval; 641 | } 642 | 643 | setenv(var, nval->c_str(), 1); 644 | } 645 | 646 | compilerver parsecompilerversion(const char *compilerversion) 647 | { 648 | const char *p = compilerversion; 649 | compilerver ver; 650 | 651 | std::strncpy(ver.s, compilerversion, sizeof(ver.s)-1); 652 | ver.major = atoi(p); 653 | 654 | while (*p && *p++ != '.') 655 | ; 656 | 657 | if (!*p) 658 | return ver; 659 | 660 | ver.minor = atoi(p); 661 | 662 | if (!*p) 663 | return ver; 664 | 665 | while (*p && *p++ != '.') 666 | ; 667 | 668 | if (!*p) 669 | return ver; 670 | 671 | ver.patch = atoi(p); 672 | return ver; 673 | } 674 | 675 | compilerver findlatestcompilerversion(const char *dir, listfilescallback cmp) 676 | { 677 | static std::vector v; 678 | static std::vector dirs; 679 | 680 | dirs.clear(); 681 | 682 | if (!listfiles(dir, &dirs, cmp)) 683 | return compilerver(); 684 | 685 | if (dirs.empty()) 686 | return compilerver(); 687 | 688 | v.clear(); 689 | 690 | for (auto &d : dirs) 691 | v.push_back(parsecompilerversion(d.c_str())); 692 | 693 | std::sort(v.begin(), v.end()); 694 | return v[v.size() - 1]; 695 | } 696 | 697 | bool fileexists(const char *file) 698 | { 699 | struct stat st; 700 | return !stat(file, &st); 701 | } 702 | 703 | bool isdirectory(const char *file, const char *prefix) 704 | { 705 | struct stat st; 706 | 707 | if (prefix) 708 | { 709 | std::string tmp = prefix; 710 | tmp += "/"; 711 | tmp += file; 712 | return !stat(tmp.c_str(), &st) && S_ISDIR(st.st_mode); 713 | } 714 | 715 | return !stat(file, &st) && S_ISDIR(st.st_mode); 716 | } 717 | 718 | bool listfiles(const char *dir, std::vector *files, 719 | listfilescallback cmp) 720 | { 721 | DIR *d = opendir(dir); 722 | dirent *de; 723 | 724 | if (!d) 725 | return false; 726 | 727 | if (files) 728 | files->clear(); 729 | 730 | while ((de = readdir(d))) 731 | { 732 | if (de->d_name[0] == '.' || !std::strcmp(de->d_name, "..")) 733 | continue; 734 | 735 | if ((!cmp || cmp(dir, de->d_name)) && files) 736 | files->push_back(de->d_name); 737 | } 738 | 739 | closedir(d); 740 | return true; 741 | } 742 | 743 | const char *getfileName(const char *file) 744 | { 745 | const char *p = strrchr(file, PATHDIV); 746 | if (!p) p = file; 747 | else ++p; 748 | return p; 749 | } 750 | 751 | 752 | bool ignoreccache(const char *f, const struct stat &) 753 | { 754 | const char *name = getfileName(f); 755 | return name && strstr(name, "ccache") != name; 756 | } 757 | 758 | bool wcrealpath(const char *file, std::string &result, 759 | realpathcmp cmp1, realpathcmp cmp2, 760 | const size_t maxSymbolicLinkDepth) 761 | { 762 | char *PATH = getenv("PATH"); 763 | const char *p = PATH ? PATH : ""; 764 | struct stat st; 765 | 766 | result.clear(); 767 | 768 | do 769 | { 770 | if (*p == ':') ++p; 771 | while (*p && *p != ':') result += *p++; 772 | 773 | result += "/"; 774 | result += file; 775 | 776 | if (!stat(result.c_str(), &st)) 777 | { 778 | if (maxSymbolicLinkDepth == 0) 779 | return true; 780 | 781 | char buf[PATH_MAX + 1]; 782 | 783 | if (realpath(result.c_str(), buf)) 784 | { 785 | result.assign(buf); 786 | } 787 | else 788 | { 789 | ssize_t len; 790 | char path[PATH_MAX]; 791 | size_t pathlen; 792 | size_t n = 0; 793 | 794 | pathlen = result.find_last_of(PATHDIV); 795 | 796 | if (pathlen == std::string::npos) pathlen = result.length(); 797 | else ++pathlen; // PATHDIV 798 | 799 | memcpy(path, result.c_str(), pathlen); // not null terminated 800 | 801 | while ((len = readlink(result.c_str(), buf, PATH_MAX)) != -1) 802 | { 803 | if (buf[0] != PATHDIV) 804 | { 805 | result.assign(path, pathlen); 806 | result.append(buf, len); 807 | } 808 | else 809 | { 810 | result.assign(buf, len); 811 | pathlen = strrchr(buf, PATHDIV) - buf + 1; // + 1: PATHDIV 812 | memcpy(path, buf, pathlen); 813 | } 814 | 815 | if (++n >= maxSymbolicLinkDepth) 816 | { 817 | result.clear(); 818 | break; 819 | } 820 | } 821 | } 822 | 823 | if ((!cmp1 || cmp1(result.c_str(), st)) && 824 | (!cmp2 || cmp2(result.c_str(), st))) 825 | break; 826 | } 827 | 828 | result.clear(); 829 | } while (*p); 830 | 831 | return !result.empty(); 832 | } 833 | 834 | bool getpathofcommand(const char *command, std::string &result) 835 | { 836 | wcrealpath(command, result, [](const char *f, const struct stat&){ 837 | return !access(f, F_OK|X_OK); 838 | }, ignoreccache); 839 | 840 | size_t pos = result.find_last_of("/"); 841 | 842 | if (pos != std::string::npos) 843 | result.resize(pos); 844 | 845 | return !result.empty(); 846 | } 847 | 848 | int runcommand(const char *command, char *buf, size_t len) 849 | { 850 | if (!len) 851 | return RUNCOMMAND_ERROR; 852 | 853 | FILE *p; 854 | size_t outputlen; 855 | 856 | if (!(p = popen(command, "r")) || !(outputlen = fread(buf, sizeof(char), len - 1, p))) 857 | { 858 | if (p) pclose(p); 859 | return RUNCOMMAND_ERROR; 860 | } 861 | 862 | buf[outputlen] = '\0'; 863 | return pclose(p); 864 | } 865 | 866 | void stripfilename(char *path) 867 | { 868 | char *p = strrchr(path, '/'); 869 | if (*p) *p = '\0'; 870 | } 871 | 872 | template 873 | static void envvar(string_vector &env, const char *varname, 874 | const char *val, T... values) 875 | { 876 | const char *vals[] = { val, values... }; 877 | 878 | std::string var = varname + std::string("="); 879 | 880 | /* g++ 4.7.2 doesn't like auto in this loop */ 881 | for (const char *val : vals) var += val; 882 | 883 | env.push_back(var); 884 | } 885 | 886 | static void fmtstring(std::ostringstream &sbuf, const char *s) 887 | { 888 | while (*s) 889 | { 890 | if (*s == '%') 891 | { 892 | if (s[1] == '%') ++s; 893 | else ERROR("fmtstring() error"); 894 | } 895 | 896 | sbuf << *s++; 897 | } 898 | } 899 | 900 | template 901 | static std::string fmtstring(std::ostringstream &buf, const char *str, 902 | T value, Args... args) 903 | { 904 | while (*str) 905 | { 906 | if (*str == '%') 907 | { 908 | if (str[1] != '%') 909 | { 910 | buf << value; 911 | fmtstring(buf, str + 1, args...); 912 | return buf.str(); 913 | } 914 | else { 915 | ++str; 916 | } 917 | } 918 | 919 | buf << *str++; 920 | } 921 | 922 | ERROR("fmtstring() error"); 923 | } 924 | 925 | template 926 | static void verbosemsg(const char *str, T value, Args... args) 927 | { 928 | std::ostringstream buf; 929 | std::string msg = fmtstring(buf, str, value, std::forward(args)...); 930 | std::cerr << PACKAGE_NAME << ": verbose: " << msg << std::endl; 931 | } 932 | 933 | template 934 | static void warn(const char *str, T value, Args... args) 935 | { 936 | std::ostringstream buf; 937 | std::string warnmsg = fmtstring(buf, str, value, std::forward(args)...); 938 | if (isterminal()) 939 | { 940 | std::cerr << KBLD PACKAGE_NAME ": warning: " KNRM << warnmsg << std::endl; 941 | return; 942 | } 943 | std::cerr << "warning: " << warnmsg << std::endl; 944 | } 945 | 946 | static void warn(const char *str) 947 | { 948 | warn("%", str); 949 | } 950 | 951 | static time_vector times; 952 | static time_point start = getticks(); 953 | 954 | static void timepoint(const char *description) 955 | { 956 | time_point now = getticks(); 957 | times.push_back(time_tuple(description, now)); 958 | } 959 | 960 | static void printtimes() 961 | { 962 | for (const auto &tp : times) 963 | { 964 | float ms = getmicrodiff(start, std::get<1>(tp)) / 1000.0f; 965 | verbosemsg("% +% ms", std::get<0>(tp), ms); 966 | } 967 | } 968 | 969 | static void parseargs(int argc, char **argv, const char *target, 970 | commandargs &cmdargs, const string_vector &env) 971 | { 972 | typedef void (*dcfun)(commandargs &cmdargs, char *arg); 973 | typedef std::tuple dc_tuple; 974 | std::vector delayedcommands; 975 | 976 | auto printheader = []() 977 | { 978 | std::cout << PACKAGE_NAME << ", Version: " << PACKAGE_VERSION << std::endl; 979 | }; 980 | 981 | for (int i = 0; i < argc; ++i) 982 | { 983 | char *arg = argv[i]; 984 | 985 | if (*arg != '-') 986 | continue; 987 | 988 | switch (*(arg+1)) 989 | { 990 | case 'c': 991 | { 992 | if (!std::strcmp(arg, "-c") || !std::strcmp(arg, "-S")) 993 | { 994 | cmdargs.iscompilestep = true; 995 | continue; 996 | } 997 | break; 998 | } 999 | case 'f': 1000 | { 1001 | if (cmdargs.iscxx) 1002 | { 1003 | if (!std::strcmp(arg, "-fexceptions")) 1004 | { 1005 | cmdargs.exceptions = 1; 1006 | continue; 1007 | } 1008 | else if (!std::strcmp(arg, "-fno-exceptions")) 1009 | { 1010 | cmdargs.exceptions = 0; 1011 | continue; 1012 | } 1013 | } 1014 | break; 1015 | } 1016 | case 'm': 1017 | { 1018 | if (!std::strcmp(arg, "-mwindows") && !cmdargs.usemingwlinker) 1019 | { 1020 | /* 1021 | * Clang doesn't support -mwindows (yet) 1022 | */ 1023 | 1024 | cmdargs.usemingwlinker = 2; 1025 | continue; 1026 | } 1027 | else if (!std::strcmp(arg, "-mdll") && !cmdargs.usemingwlinker) 1028 | { 1029 | /* 1030 | * Clang doesn't support -mdll (yet) 1031 | */ 1032 | 1033 | cmdargs.usemingwlinker = 3; 1034 | continue; 1035 | } 1036 | else if (!std::strcmp(arg, "-mconsole") && !cmdargs.usemingwlinker) 1037 | { 1038 | /* 1039 | * Clang doesn't support -mconsole (yet) 1040 | */ 1041 | 1042 | cmdargs.usemingwlinker = 4; 1043 | continue; 1044 | } 1045 | break; 1046 | } 1047 | case 'o': 1048 | { 1049 | if (!std::strncmp(arg, "-o", STRLEN("-o"))) 1050 | { 1051 | cmdargs.islinkstep = true; 1052 | continue; 1053 | } 1054 | break; 1055 | } 1056 | case 'x': 1057 | { 1058 | if (!std::strncmp(arg, "-x", STRLEN("-x"))) 1059 | { 1060 | const char *p = arg+STRLEN("-x"); 1061 | 1062 | if (!*p) 1063 | { 1064 | p = argv[++i]; 1065 | 1066 | if (i >= argc) 1067 | ERROR("missing argument for '-x'"); 1068 | } 1069 | 1070 | auto checkcxx = [&]() 1071 | { 1072 | if (!cmdargs.iscxx) 1073 | { 1074 | cmdargs.iscxx = true; 1075 | findcxxheaders(target, cmdargs); 1076 | } 1077 | }; 1078 | 1079 | if (!std::strcmp(p, "c")) cmdargs.iscxx = false; 1080 | else if (!std::strcmp(p, "c-header")) cmdargs.iscxx = false; 1081 | else if (!std::strcmp(p, "c++")) checkcxx(); 1082 | else if (!std::strcmp(p, "c++-header")) checkcxx(); 1083 | else ERROR("given language not supported"); 1084 | continue; 1085 | } 1086 | break; 1087 | } 1088 | case 'O': 1089 | { 1090 | if (!std::strncmp(arg, "-O", STRLEN("-O"))) 1091 | { 1092 | int &level = cmdargs.optimizationlevel; 1093 | 1094 | arg += STRLEN("-O"); 1095 | 1096 | if (*arg == 's') level = optimize::SIZE_1; 1097 | else if (*arg == 'z') level = optimize::SIZE_2; 1098 | else if (!strcmp(arg, "fast")) level = optimize::FAST; 1099 | else { 1100 | level = std::atoi(arg); 1101 | if (level > optimize::LEVEL_3) level = optimize::LEVEL_3; 1102 | else if (level < optimize::LEVEL_0) level = optimize::LEVEL_0; 1103 | } 1104 | continue; 1105 | } 1106 | break; 1107 | } 1108 | break; 1109 | } 1110 | 1111 | /* 1112 | * Everything with COMMANDPREFIX belongs to us 1113 | */ 1114 | 1115 | if (!std::strncmp(arg, "--", STRLEN("--"))) 1116 | ++arg; 1117 | 1118 | if (std::strncmp(arg, COMMANDPREFIX, STRLEN(COMMANDPREFIX))) 1119 | continue; 1120 | 1121 | arg += STRLEN(COMMANDPREFIX); 1122 | 1123 | #define INVALID_ARGUMENT else goto invalid_argument 1124 | 1125 | switch (*arg) 1126 | { 1127 | case 'a': 1128 | { 1129 | if (!std::strcmp(arg, "arch") || !std::strcmp(arg, "a")) 1130 | { 1131 | const char *end = std::strchr(target, '-'); 1132 | 1133 | if (!end) 1134 | { 1135 | std::cerr << "internal error (could not determine arch)" 1136 | << std::endl; 1137 | std::exit(EXIT_FAILURE); 1138 | } 1139 | 1140 | std::string arch(target, end-target); 1141 | std::cout << arch << std::endl; 1142 | std::exit(EXIT_SUCCESS); 1143 | } 1144 | else if (!std::strcmp(arg, "append-exe")) { 1145 | cmdargs.appendexe = true; 1146 | } INVALID_ARGUMENT; 1147 | break; 1148 | } 1149 | case 'e': 1150 | { 1151 | if (!std::strncmp(arg, "env-", STRLEN("env-")) || 1152 | !std::strncmp(arg, "e-", STRLEN("e-"))) 1153 | { 1154 | bool found = false; 1155 | 1156 | while (*++arg != '-'); 1157 | ++arg; 1158 | 1159 | for (char *p = arg; *p; ++p) *p = toupper(*p); 1160 | 1161 | size_t i = 0; 1162 | for (const char *var : ENVVARS) 1163 | { 1164 | if (!std::strcmp(arg, var)) 1165 | { 1166 | const char *val = env[i].c_str(); 1167 | val += std::strlen(var) + 1; /* skip variable name */ 1168 | 1169 | std::cout << val << std::endl; 1170 | found = true; 1171 | 1172 | break; 1173 | } 1174 | 1175 | if (found) break; 1176 | 1177 | ++i; 1178 | } 1179 | 1180 | if (!found) 1181 | { 1182 | std::cerr << "environment variable " << arg << " not found" 1183 | << std::endl 1184 | << "available environment variables: " 1185 | << std::endl; 1186 | 1187 | for (const char *var : ENVVARS) 1188 | std::cerr << " " << var << std::endl; 1189 | 1190 | std::exit(EXIT_FAILURE); 1191 | } 1192 | std::exit(EXIT_SUCCESS); 1193 | } 1194 | else if (!std::strcmp(arg, "env") || !std::strcmp(arg, "e")) 1195 | { 1196 | for (const auto &v : env) std::cout << v << " "; 1197 | std::cout << std::endl; 1198 | std::exit(EXIT_SUCCESS); 1199 | } INVALID_ARGUMENT; 1200 | break; 1201 | } 1202 | case 'h': 1203 | { 1204 | if (!std::strcmp(arg, "help") || !std::strcmp(arg, "h")) 1205 | { 1206 | printheader(); 1207 | 1208 | auto printcmdhelp = [&](const char *cmd, const std::string &text) 1209 | { 1210 | std::cout << " " << COMMANDPREFIX << cmd << ": " << text << std::endl; 1211 | }; 1212 | 1213 | printcmdhelp("version", "show version"); 1214 | printcmdhelp("target", "show target"); 1215 | 1216 | printcmdhelp("env-", std::string("show environment variable [e.g.: ") + 1217 | std::string(COMMANDPREFIX) + std::string("env-ld]")); 1218 | 1219 | printcmdhelp("env", "show all environment variables at once"); 1220 | printcmdhelp("arch", "show target architecture"); 1221 | printcmdhelp("static-runtime", "link runtime statically"); 1222 | printcmdhelp("append-exe", "append .exe automatically to output filenames"); 1223 | printcmdhelp("use-mingw-linker", "link with mingw"); 1224 | printcmdhelp("no-intrin", "do not use clang intrinsics"); 1225 | printcmdhelp("verbose", "enable verbose messages"); 1226 | 1227 | std::exit(EXIT_SUCCESS); 1228 | } INVALID_ARGUMENT; 1229 | break; 1230 | } 1231 | case 'n': 1232 | { 1233 | if (!std::strncmp(arg, "no-intrin", STRLEN("no-intrin"))) 1234 | { 1235 | cmdargs.nointrinsics = true; 1236 | continue; 1237 | } INVALID_ARGUMENT; 1238 | break; 1239 | } 1240 | case 's': 1241 | { 1242 | if (!std::strcmp(arg, "static-runtime")) 1243 | { 1244 | static constexpr const char* GCCRUNTIME = "-static-libgcc"; 1245 | static constexpr const char* LIBSTDCXXRUNTIME = "-static-libstdc++"; 1246 | 1247 | /* 1248 | * Postpone execution to later 1249 | * We don't know yet, if it is the link step or not 1250 | */ 1251 | auto staticruntime = [](commandargs &cmdargs, char *arg) 1252 | { 1253 | /* 1254 | * Avoid "argument unused during compilation: '...'" 1255 | */ 1256 | if (!cmdargs.islinkstep) 1257 | { 1258 | if (cmdargs.verbose) 1259 | verbosemsg("ignoring %", arg); 1260 | return; 1261 | } 1262 | 1263 | if (cmdargs.iscxx) 1264 | { 1265 | cmdargs.cxxflags.push_back(GCCRUNTIME); 1266 | cmdargs.cxxflags.push_back(LIBSTDCXXRUNTIME); 1267 | } 1268 | else { 1269 | cmdargs.cflags.push_back(GCCRUNTIME); 1270 | } 1271 | }; 1272 | 1273 | delayedcommands.push_back(dc_tuple(staticruntime, arg-STRLEN(COMMANDPREFIX))); 1274 | } INVALID_ARGUMENT; 1275 | break; 1276 | } 1277 | case 't': 1278 | { 1279 | if (!std::strcmp(arg, "target") || !std::strcmp(arg, "t")) 1280 | { 1281 | std::cout << target << std::endl; 1282 | std::exit(EXIT_SUCCESS); 1283 | } INVALID_ARGUMENT; 1284 | break; 1285 | } 1286 | case 'u': 1287 | { 1288 | if (!std::strcmp(arg, "use-mingw-linker")) 1289 | { 1290 | auto usemingwlinker = [](commandargs &cmdargs, char *arg) 1291 | { 1292 | if (!cmdargs.islinkstep) 1293 | { 1294 | if (cmdargs.verbose) 1295 | verbosemsg("ignoring %", arg); 1296 | return; 1297 | } 1298 | 1299 | cmdargs.usemingwlinker = 1; 1300 | }; 1301 | 1302 | delayedcommands.push_back(dc_tuple(usemingwlinker, arg-STRLEN(COMMANDPREFIX))); 1303 | continue; 1304 | } INVALID_ARGUMENT; 1305 | break; 1306 | } 1307 | case 'v': 1308 | { 1309 | if (!std::strcmp(arg, "version") || !std::strcmp(arg, "v")) 1310 | { 1311 | printheader(); 1312 | std::cout << "Copyright (C) 2013-2017 Thomas Poechtrager" << std::endl; 1313 | std::cout << "License: GPL v2" << std::endl; 1314 | std::cout << "Bugs / Wishes: " << PACKAGE_BUGREPORT << std::endl; 1315 | std::exit(EXIT_SUCCESS); 1316 | } 1317 | else if (!std::strcmp(arg, "verbose")) { 1318 | cmdargs.verbose = true; 1319 | } INVALID_ARGUMENT; 1320 | break; 1321 | } 1322 | default: 1323 | { 1324 | invalid_argument:; 1325 | printheader(); 1326 | std::cerr << "invalid argument: " << COMMANDPREFIX << arg << std::endl; 1327 | std::exit(EXIT_FAILURE); 1328 | } 1329 | } 1330 | 1331 | #undef INVALID_ARGUMENT 1332 | } 1333 | 1334 | if (cmdargs.islinkstep && cmdargs.iscompilestep) 1335 | { 1336 | /* w32-clang file.c -c -o file.o */ 1337 | cmdargs.islinkstep = false; 1338 | } 1339 | else if (!cmdargs.islinkstep && !cmdargs.iscompilestep) 1340 | { 1341 | /* w32-clang file.c */ 1342 | cmdargs.islinkstep = true; 1343 | } 1344 | 1345 | for (auto dc : delayedcommands) 1346 | { 1347 | auto fun = std::get<0>(dc); 1348 | fun(cmdargs, std::get<1>(dc)); 1349 | } 1350 | } 1351 | 1352 | int main(int argc, char **argv) 1353 | { 1354 | std::string target; 1355 | int targettype = -1; 1356 | const char *e = std::strrchr(argv[0], '/'); 1357 | const char *p = nullptr; 1358 | 1359 | bool iscxx = false; 1360 | string_vector intrinpaths; 1361 | string_vector stdpaths; 1362 | string_vector cxxpaths; 1363 | string_vector linkerflags; 1364 | std::string compiler; 1365 | std::string compilerpath; 1366 | std::string compilerbinpath; 1367 | string_vector env; 1368 | string_vector args; 1369 | char **cargs = nullptr; 1370 | int cargsi = 0; 1371 | string_vector cflags; 1372 | string_vector cxxflags; 1373 | 1374 | commandargs cmdargs(intrinpaths, stdpaths, cxxpaths, cflags, 1375 | cxxflags, linkerflags, target, 1376 | compiler, compilerpath, compilerbinpath, env, 1377 | args, iscxx); 1378 | 1379 | timepoint("start"); 1380 | 1381 | if (!e) e = argv[0]; 1382 | else ++e; 1383 | 1384 | p = std::strrchr(e, '-'); 1385 | if (!p++ || std::strncmp(p, "clang", STRLEN("clang"))) 1386 | { 1387 | std::cerr << "invalid invocation name: clang should be followed " 1388 | "after target (e.g.: w32-clang)" << std::endl; 1389 | return 1; 1390 | } 1391 | 1392 | /* 1393 | * Check if we want the C or the C++ compiler 1394 | */ 1395 | 1396 | p += STRLEN("clang"); 1397 | if (!std::strcmp(p, "++")) iscxx = true; 1398 | else if (*p) { 1399 | std::cerr << "invalid invocation name: ++ (or nothing) should be " 1400 | "followed after clang (e.g.: w32-clang++)" << std::endl; 1401 | return 1; 1402 | } 1403 | 1404 | /* 1405 | * Check if we should target win32 or win64... 1406 | */ 1407 | 1408 | find_target_and_headers:; 1409 | 1410 | if (const char *triple = findtriple(e, targettype)) 1411 | { 1412 | target = triple; 1413 | findheaders(cmdargs, target); 1414 | } 1415 | else 1416 | { 1417 | if (!std::strncmp(e, "w32", STRLEN("w32"))) 1418 | { 1419 | const char *t = findtarget32(cmdargs); 1420 | target = t ? t : ""; 1421 | targettype = TARGET_WIN32; 1422 | } 1423 | else if (!std::strncmp(e, "w64", STRLEN("w64"))) 1424 | { 1425 | const char *t = findtarget64(cmdargs); 1426 | target = t ? t : ""; 1427 | targettype = TARGET_WIN64; 1428 | } 1429 | } 1430 | 1431 | if (targettype == -1) 1432 | { 1433 | std::cerr << "invalid target: " << e << std::endl; 1434 | return 1; 1435 | } 1436 | else if (target.empty()) 1437 | { 1438 | const char *type; 1439 | std::string desc; 1440 | 1441 | if (getenv("MINGW_PATH")) 1442 | { 1443 | warn("MINGW_PATH env variable does not point to any " 1444 | "valid mingw installation for the current target!"); 1445 | 1446 | #ifdef HAVE_UNSETENV 1447 | unsetenv("MINGW_PATH"); 1448 | #else 1449 | std::exit(EXIT_FAILURE); 1450 | #endif 1451 | 1452 | goto find_target_and_headers; 1453 | } 1454 | 1455 | switch (targettype) 1456 | { 1457 | case TARGET_WIN32: type = "32 bit"; break; 1458 | case TARGET_WIN64: type = "64 bit"; break; 1459 | default: type = nullptr; 1460 | } 1461 | 1462 | desc = std::string("mingw-w64 (") + std::string(type) + std::string(")"); 1463 | 1464 | std::cerr << "cannot find " << desc << " installation" << std::endl; 1465 | std::cerr << "make sure " << desc << " is installed on your system" 1466 | << std::endl; 1467 | 1468 | std::cerr << "if you have moved your mingw installation, " 1469 | "then re-run the installation process" << std::endl; 1470 | return 1; 1471 | } 1472 | 1473 | /* 1474 | * Lookup C and C++ include paths 1475 | */ 1476 | 1477 | if (stdpaths.empty()) 1478 | { 1479 | std::cerr << "cannot find " << target 1480 | << " C headers" << std::endl; 1481 | 1482 | std::cerr << "make sure " << target 1483 | << " C headers are installed on your system " << std::endl; 1484 | return 1; 1485 | } 1486 | 1487 | if (!findcxxheaders(target.c_str(), cmdargs) && iscxx) 1488 | { 1489 | std::cerr << "cannot find " << target 1490 | << " C++ headers" << std::endl; 1491 | 1492 | std::cerr << "make sure " << target 1493 | << " C++ headers are installed on your system " 1494 | << std::endl; 1495 | return 1; 1496 | } 1497 | 1498 | /* 1499 | * Setup compiler command 1500 | */ 1501 | 1502 | if (iscxx) 1503 | { 1504 | compiler = "clang++"; 1505 | 1506 | if (STRLEN(CXXFLAGS) > 0) 1507 | cxxflags.push_back(CXXFLAGS); 1508 | } 1509 | else 1510 | { 1511 | compiler = "clang"; 1512 | 1513 | if (STRLEN(CFLAGS) > 0) 1514 | cflags.push_back(CFLAGS); 1515 | } 1516 | 1517 | /* 1518 | * Setup environment variables 1519 | */ 1520 | 1521 | for (const char *var : ENVVARS) 1522 | { 1523 | size_t len = std::strlen(var); 1524 | char *buf = new char[1+len+1]; 1525 | 1526 | buf[len+1] = '\0'; 1527 | *buf++ = '-'; 1528 | 1529 | for (size_t i = 0; i < len; ++i) 1530 | buf[i] = tolower(var[i]); 1531 | 1532 | envvar(env, var, target.c_str(), --buf); 1533 | delete[] buf; 1534 | } 1535 | 1536 | /* 1537 | * Parse command arguments late, 1538 | * when we know our environment already 1539 | */ 1540 | 1541 | parseargs(argc, argv, target.c_str(), cmdargs, env); /* may not return */ 1542 | 1543 | /* 1544 | * Setup compiler Arguments 1545 | */ 1546 | 1547 | if (cmdargs.islinkstep && cmdargs.usemingwlinker) 1548 | { 1549 | compiler = target + (iscxx ? "-g++" : "-gcc"); 1550 | 1551 | if (cmdargs.usemingwlinker > 1) 1552 | { 1553 | constexpr const char *desc[] = { "-mwindows", "-mdll", "-mconsole" }; 1554 | size_t index = cmdargs.usemingwlinker-2; 1555 | warn("linking with % because of unimplemented %", compiler, desc[index]); 1556 | } 1557 | } 1558 | 1559 | if ((targettype == TARGET_WIN64) && 1560 | (cmdargs.iscompilestep || cmdargs.islinkstep) && 1561 | (cmdargs.optimizationlevel >= optimize::LEVEL_1)) 1562 | { 1563 | /* 1564 | * Workaround for a bug in the MinGW math.h header, 1565 | * fabs() and friends getting miscompiled without 1566 | * defining __CRT__NO_INLINE, because there is 1567 | * something wrong with their inline definition. 1568 | */ 1569 | char *p; 1570 | if (!(p = getenv("WCLANG_NO_CRT_INLINE_WORKAROUND")) || *p == '0') 1571 | { 1572 | // warn("defining __CRT__NO_INLINE to work around bugs in" 1573 | // "the mingw math.h header"); 1574 | cxxflags.push_back("-D__CRT__NO_INLINE"); 1575 | } 1576 | } 1577 | 1578 | if (compiler[0] != '/') 1579 | { 1580 | std::string tmp; 1581 | 1582 | if (!getpathofcommand(compiler.c_str(), compilerbinpath)) 1583 | { 1584 | std::cerr << "cannot find '" << compiler << "' executable" 1585 | << std::endl; 1586 | return 1; 1587 | } 1588 | 1589 | tmp.swap(compiler); 1590 | 1591 | compiler = compilerbinpath; 1592 | compiler += "/"; 1593 | compiler += tmp; 1594 | } 1595 | 1596 | { 1597 | /* 1598 | * Find MinGW binaries (required for linking) 1599 | */ 1600 | std::string gcc = target + (iscxx ? "-g++" : "-gcc"); 1601 | std::string path; 1602 | 1603 | const char *mingwpath = getenv("MINGW_PATH"); 1604 | 1605 | if (!mingwpath) 1606 | { 1607 | #ifdef MINGW_PATH 1608 | if (*MINGW_PATH) mingwpath = MINGW_PATH; 1609 | #endif 1610 | } 1611 | 1612 | if (mingwpath && *mingwpath) 1613 | concatenvvariable("PATH", mingwpath); 1614 | 1615 | if (!getpathofcommand(gcc.c_str(), path)) 1616 | { 1617 | std::cerr << "cannot find " << gcc << " executable" << std::endl; 1618 | return 1; 1619 | } 1620 | 1621 | #if 0 1622 | /* 1623 | * COMPILER_PATH would be a perfect solution to get rid of the 1624 | * MinGW-GCC symlinks, but unfortunately it causes MinGW-GCC 1625 | * to use the wrong assembler/linker on some systems. 1626 | * GCC is invoked for assembling (prior to clang 3.5) and linking. 1627 | */ 1628 | concatenvvariable("COMPILER_PATH", path, &cmdargs.compilerpath); 1629 | #endif 1630 | 1631 | if (cmdargs.islinkstep) 1632 | { 1633 | /* https://github.com/tpoechtrager/wclang/issues/22 */ 1634 | 1635 | std::string command = cmdargs.target + "-gcc -print-libgcc-file-name"; 1636 | char output[4096]; 1637 | 1638 | if (runcommand(command.c_str(), output, sizeof(output)) == 0) 1639 | { 1640 | stripfilename(output); 1641 | linkerflags.push_back(std::string("-L") + output); 1642 | } 1643 | } 1644 | 1645 | 1646 | args.push_back(compiler); 1647 | 1648 | auto pushcompilerflags = [&](const string_vector &flags) 1649 | { 1650 | for (const auto &flag : flags) 1651 | args.push_back(flag); 1652 | }; 1653 | 1654 | pushcompilerflags(iscxx ? cxxflags : cflags); 1655 | pushcompilerflags(linkerflags); 1656 | 1657 | if (!cmdargs.islinkstep || !cmdargs.usemingwlinker) 1658 | { 1659 | char *p; 1660 | 1661 | args.push_back(CLANG_TARGET_OPT); 1662 | args.push_back(target); 1663 | 1664 | /* 1665 | * Prevent clang from including /usr/include in 1666 | * case a file is not found in our directories 1667 | */ 1668 | args.push_back("-nostdinc"); 1669 | args.push_back("-nostdinc++"); 1670 | args.push_back("-Qunused-arguments"); 1671 | 1672 | auto pushdirs = [&](const string_vector &paths) 1673 | { 1674 | for (const auto &dir : paths) 1675 | { 1676 | args.push_back("-isystem"); 1677 | args.push_back(dir); 1678 | } 1679 | }; 1680 | 1681 | if (!findintrinheaders(cmdargs, compilerbinpath)) 1682 | { 1683 | if (!cmdargs.nointrinsics) 1684 | warn("cannot find clang intrinsics directory"); 1685 | } 1686 | else if (cmdargs.clangversion == compilerver(3, 5, 0)) 1687 | { 1688 | /* 1689 | * Workaround for clang 3.5.0 to get rid of 1690 | * error: redeclaration of '_scanf_l' cannot add 'dllimport' attribute 1691 | */ 1692 | args.push_back("-D_STDIO_S_DEFINED"); 1693 | } 1694 | 1695 | if (cmdargs.verbose) 1696 | verbosemsg("detected clang version: %", cmdargs.clangversion.str()); 1697 | 1698 | if (cmdargs.exceptions != 0 && (cmdargs.clangversion < compilerver(3, 7, 0) || 1699 | (targettype == TARGET_WIN32 && cmdargs.clangversion < compilerver(6, 0, 0)))) 1700 | { 1701 | char *p; 1702 | if (!(p = getenv("WCLANG_FORCE_CXX_EXCEPTIONS")) || *p == '0') 1703 | { 1704 | if (cmdargs.exceptions == 1) 1705 | { 1706 | warn("-fexceptions will be replaced with -fno-exceptions: " 1707 | "exceptions are not supported (yet)"); 1708 | 1709 | std::cerr << "set WCLANG_FORCE_CXX_EXCEPTIONS to 1 " 1710 | << "(env. variable) to force C++ exceptions" << std::endl; 1711 | } 1712 | 1713 | args.push_back("-fno-exceptions"); 1714 | } 1715 | else { 1716 | cmdargs.exceptions = -1; 1717 | } 1718 | } 1719 | 1720 | if (targettype == TARGET_WIN32 && cmdargs.clangversion >= compilerver(6, 0, 0)) 1721 | { 1722 | args.push_back("-fsjlj-exceptions"); 1723 | } 1724 | 1725 | if ((p = getenv("WCLANG_NO_INTEGRATED_AS")) && *p == '1') 1726 | args.push_back("-no-integrated-as"); 1727 | 1728 | /* 1729 | * For libstdc++ 6, the C++ includes must appear before the standard 1730 | * includes. 1731 | * 1732 | * libstdc++ 6 is very picky if you use -isystem for system include 1733 | * directories. It needs the C++ path first, otherwise it errors out 1734 | * with "'stdlib.h' file not found". 1735 | * 1736 | * This is a known problem and apparently will not be fixed upstream: 1737 | * 1738 | * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129 1739 | */ 1740 | pushdirs(intrinpaths); 1741 | pushdirs(cxxpaths); 1742 | pushdirs(stdpaths); 1743 | } 1744 | } 1745 | 1746 | for (int i = 1; i < argc; ++i) 1747 | { 1748 | const char *arg = argv[i]; 1749 | static constexpr size_t BUFSIZE = STRLEN(COMMANDPREFIX)+2; 1750 | char buf[BUFSIZE]; 1751 | 1752 | if (!std::strncmp(arg, COMMANDPREFIX, STRLEN(COMMANDPREFIX))) 1753 | continue; 1754 | 1755 | if (cmdargs.exceptions == 1 && !std::strcmp(arg, "-fexceptions")) 1756 | continue; 1757 | 1758 | *buf = '-'; 1759 | std::memcpy(buf+1, COMMANDPREFIX, BUFSIZE-1); 1760 | 1761 | if (!std::strncmp(arg, buf, BUFSIZE)) 1762 | continue; 1763 | 1764 | if (cmdargs.islinkstep && cmdargs.usemingwlinker) 1765 | { 1766 | if (!std::strncmp(arg, "-Qunused", STRLEN("-Qunused"))) 1767 | continue; 1768 | } 1769 | 1770 | args.push_back(argv[i]); 1771 | } 1772 | 1773 | cargs = new char* [args.size()+2]; 1774 | cargs[args.size()] = nullptr; 1775 | 1776 | for (const auto &opt : args) 1777 | cargs[cargsi++] = strdup(opt.c_str()); 1778 | 1779 | if (cmdargs.appendexe) 1780 | appendexetooutputname(cargs); 1781 | 1782 | /* 1783 | * Execute command 1784 | */ 1785 | 1786 | if (cmdargs.verbose) 1787 | { 1788 | std::string commandin, commandout; 1789 | 1790 | for (int i = 0; i < argc; ++i) 1791 | { 1792 | if (i) commandin += " "; 1793 | commandin += argv[i]; 1794 | } 1795 | 1796 | for (char **arg = cargs; *arg; ++arg) 1797 | { 1798 | if (arg != cargs) commandout += " "; 1799 | commandout += *arg; 1800 | } 1801 | 1802 | timepoint("end"); 1803 | verbosemsg("command in: %", commandin); 1804 | verbosemsg("command out: %", commandout); 1805 | printtimes(); 1806 | } 1807 | 1808 | execvp(compiler.c_str(), cargs); 1809 | 1810 | std::cerr << "invoking compiler failed" << std::endl; 1811 | std::cerr << compiler << " not installed?" << std::endl; 1812 | return 1; 1813 | } 1814 | -------------------------------------------------------------------------------- /src/wclang.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "config.h" 8 | 9 | static inline void ERRORMSG(const char *msg, const char *file, 10 | int line, const char *func) 11 | { 12 | std::cerr << "runtime error: " << msg << std::endl; 13 | std::cerr << file << " " << func << "():"; 14 | std::cerr << line << std::endl; 15 | 16 | std::exit(EXIT_FAILURE); 17 | } 18 | 19 | __attribute__ ((noreturn)) 20 | static inline void ERRORMSG(const char *msg, const char *file, 21 | int line, const char *func); 22 | 23 | #define ERROR(msg) \ 24 | do { \ 25 | ERRORMSG(msg, __FILE__, __LINE__, __func__); \ 26 | } while (0) 27 | 28 | template 29 | constexpr size_t STRLEN(const T &str) 30 | { 31 | static_assert(sizeof(*str) == 1, "not a string"); 32 | return sizeof(T)-1; 33 | } 34 | 35 | static_assert(STRLEN("test string") == 11, ""); 36 | 37 | static inline void clear(std::stringstream &s) 38 | { 39 | s.str(std::string()); 40 | } 41 | 42 | typedef unsigned long long ullong; 43 | typedef std::vector string_vector; 44 | 45 | #define KNRM "\x1B[0m" 46 | #define KBLD "\x1B[1m" 47 | #define PATHDIV '/' 48 | 49 | void concatenvvariable(const char *var, const std::string val, std::string *nval = nullptr); 50 | 51 | typedef bool (*listfilescallback)(const char *dir, const char *file); 52 | bool fileexists(const char *file); 53 | bool isdirectory(const char *file, const char *prefix); 54 | bool listfiles(const char *dir, std::vector *files, listfilescallback cmp = nullptr); 55 | const char *getfileName(const char *file); 56 | 57 | typedef bool (*realpathcmp)(const char *file, const struct stat &st); 58 | bool ignoreccache(const char *f, const struct stat &); 59 | bool wcrealpath(const char *file, std::string &result, realpathcmp cmp1 = nullptr, 60 | realpathcmp cmp2 = nullptr, const size_t maxSymobolicLinkDepth = 1000); 61 | bool getpathofcommand(const char *bin, std::string &result); 62 | 63 | constexpr int RUNCOMMAND_ERROR = -100000; 64 | int runcommand(const char *command, char *buf, size_t len); 65 | 66 | void stripfilename(char *path); 67 | 68 | struct compilerversion; 69 | typedef compilerversion compilerver; 70 | compilerver parsecompilerversion(const char *compilerversion); 71 | compilerver findlatestcompilerversion(const char *dir, listfilescallback cmp = nullptr); 72 | 73 | #undef major 74 | #undef minor 75 | #undef patch 76 | 77 | struct compilerversion { 78 | constexpr compilerversion(int major, int minor, int patch = 0) 79 | : major(major), minor(minor), patch(patch), s() {} 80 | constexpr compilerversion() : major(), minor(), patch(), s() {} 81 | 82 | constexpr int num() const 83 | { 84 | return major * 10000 + minor * 100 + patch; 85 | } 86 | 87 | constexpr bool operator>(const compilerversion &cv) const 88 | { 89 | return num() > cv.num(); 90 | } 91 | 92 | constexpr bool operator>=(const compilerversion &cv) const 93 | { 94 | return num() >= cv.num(); 95 | } 96 | 97 | constexpr bool operator<(const compilerversion &cv) const 98 | { 99 | return num() < cv.num(); 100 | } 101 | 102 | constexpr bool operator<=(const compilerversion &cv) const 103 | { 104 | return num() <= cv.num(); 105 | } 106 | 107 | constexpr bool operator==(const compilerversion &cv) const 108 | { 109 | return num() == cv.num(); 110 | } 111 | 112 | constexpr bool operator!=(const compilerversion &cv) const 113 | { 114 | return num() != cv.num(); 115 | } 116 | 117 | bool operator!=(const char *val) const 118 | { 119 | size_t c = 0; 120 | const char *p = val; 121 | 122 | while (*p) 123 | { 124 | if (*p++ == '.') 125 | ++c; 126 | } 127 | 128 | switch (c) 129 | { 130 | case 1: 131 | return shortstr() != val; 132 | case 2: 133 | return str() != val; 134 | default: 135 | return true; 136 | } 137 | } 138 | 139 | std::string str() const 140 | { 141 | std::stringstream tmp; 142 | tmp << major << "." << minor << "." << patch; 143 | return tmp.str(); 144 | } 145 | 146 | std::string shortstr() const 147 | { 148 | std::stringstream tmp; 149 | tmp << major << "." << minor; 150 | return tmp.str(); 151 | } 152 | 153 | int major; 154 | int minor; 155 | int patch; 156 | char s[12]; 157 | }; 158 | 159 | enum optimize { 160 | LEVEL_0, 161 | LEVEL_1, 162 | LEVEL_3, 163 | FAST, 164 | SIZE_1, 165 | SIZE_2 166 | }; 167 | 168 | struct commandargs { 169 | bool verbose; 170 | compilerver clangversion; 171 | compilerver mingwversion; 172 | string_vector &intrinpaths; 173 | string_vector &stdpaths; 174 | string_vector &cxxpaths; 175 | string_vector &cflags; 176 | string_vector &cxxflags; 177 | string_vector &linkerflags; 178 | std::string ⌖ 179 | std::string &compiler; 180 | std::string &compilerpath; 181 | std::string &compilerbinpath; 182 | string_vector &env; 183 | string_vector &args; 184 | bool &iscxx; 185 | bool appendexe; 186 | bool iscompilestep; 187 | bool islinkstep; 188 | bool nointrinsics; 189 | int exceptions; 190 | int optimizationlevel; 191 | int usemingwlinker; 192 | 193 | commandargs(string_vector &intrinpaths, string_vector &stdpaths, string_vector &cxxpaths, 194 | string_vector &cflags, string_vector &cxxflags, 195 | string_vector &linkerflags, std::string &target, std::string &compiler, 196 | std::string &compilerpath, std::string &compilerbinpath, string_vector &env, 197 | string_vector &args, bool &iscxx) 198 | : 199 | verbose(false), intrinpaths(intrinpaths), stdpaths(stdpaths), 200 | cxxpaths(cxxpaths), cflags(cflags), cxxflags(cxxflags), 201 | linkerflags(linkerflags), target(target), compiler(compiler), compilerpath(compilerpath), 202 | compilerbinpath(compilerbinpath), env(env), args(args), iscxx(iscxx), 203 | appendexe(false), iscompilestep(false), islinkstep(false), nointrinsics(false), 204 | exceptions(-1), optimizationlevel(0), usemingwlinker(0) {} 205 | } __attribute__ ((aligned (8))); 206 | -------------------------------------------------------------------------------- /src/wclang_time.cpp: -------------------------------------------------------------------------------- 1 | /*********************************************************************** 2 | * wclang * 3 | * Copyright (C) 2013-2017 Thomas Poechtrager * 4 | * t.poechtrager@gmail.com * 5 | * * 6 | * This program is free software; you can redistribute it and/or * 7 | * modify it under the terms of the GNU General Public License * 8 | * as published by the Free Software Foundation; either version 2 * 9 | * of the License, or (at your option) any later version. * 10 | * * 11 | * This program is distributed in the hope that it will be useful, * 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 14 | * GNU General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU General Public License * 17 | * along with this program; if not, write to the Free Software * 18 | * Foundation, Inc., * 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 20 | ***********************************************************************/ 21 | 22 | #include 23 | #include 24 | #include "wclang.h" 25 | #include "wclang_time.h" 26 | 27 | #ifdef HAVE_STD_CHRONO 28 | time_point getticks() 29 | { 30 | return std::chrono::steady_clock::now(); 31 | } 32 | ullong getmicrodiff(time_point &start, time_point time) 33 | { 34 | using namespace std; 35 | using namespace std::chrono; 36 | return duration_cast>(time-start).count(); 37 | } 38 | #else 39 | /* 40 | * steady_clock and monotonic_clock are broken in 41 | * debian/ubuntu g++-4.6 and g++-4.7 42 | * http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=710220 43 | */ 44 | time_point getticks() 45 | { 46 | struct timeval tv; 47 | if (gettimeofday(&tv, NULL) == 0) 48 | return (time_point)((tv.tv_sec*1000000ULL)+tv.tv_usec); 49 | ERROR("gettimeofday() failed"); 50 | } 51 | ullong getmicrodiff(time_point &start, time_point time) 52 | { 53 | return time-start; 54 | } 55 | #endif 56 | -------------------------------------------------------------------------------- /src/wclang_time.h: -------------------------------------------------------------------------------- 1 | #ifdef HAVE_STD_CHRONO 2 | #include 3 | typedef std::chrono::steady_clock::time_point time_point; 4 | ullong getmicrodiff(time_point &start, time_point time); 5 | #else 6 | #include 7 | typedef ullong time_point; 8 | ullong getmicrodiff(time_point &start, time_point time); 9 | #endif 10 | 11 | time_point getticks(); 12 | 13 | typedef std::tuple time_tuple; 14 | typedef std::vector time_vector; 15 | --------------------------------------------------------------------------------