diff --git a/COPYING.LIB b/COPYING.LIB new file mode 100644 index 0000000..4362b49 --- /dev/null +++ b/COPYING.LIB @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/README.md b/README.md index 152d3f3..032d0ed 100644 --- a/README.md +++ b/README.md @@ -78,3 +78,5 @@ Unless you explicitly state otherwise, any contribution intentionally submitted The list of authors for copyright purposes is in the [AUTHORS](AUTHORS) file. Significant portions of AccessKit are derived from Chromium and are covered by its [BSD-style license](LICENSE.chromium). + +The Meson build system for accesskit-c is licensed under the [GNU Lesser General Public License, Version 2.1](COPYING.LIB). Note that this license applies only to the build system, not to the accesskit-c library itself. diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..0f29c95 --- /dev/null +++ b/meson.build @@ -0,0 +1,484 @@ +# Derived from the librsvg Meson build +# Copyright (c) 2024 L. E. Segovia +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see . + +project('accesskit-c', + 'c', + meson_version: '>= 1.3.0', + default_options: [ + 'pkgconfig.relocatable=true', + ] +) + +host_system = host_machine.system() +cc = meson.get_compiler('c') + +# MSRV - Minimum Supported Rust Version +# If you change this, please update these: +# - the "rust-version" value in Cargo.toml +msrv = '1.75.0' +cargo = find_program('cargo', version:'>= @0@'.format(msrv)) +cargo_wrapper = find_program('meson/cargo_wrapper.py', native: true) +rustc = find_program('rustc', version:'>= @0@'.format(msrv)) +makedef = find_program('meson/makedef.py', native: true) +project_version_script = find_program('meson/project_version.py', native: true) + +py = import('python') + +python = py.find_installation() + +appkit_dep = dependency('appleframeworks', modules: 'AppKit', + required: host_system == 'darwin') +m_dep = cc.find_library('m', required: false) +uiautomationcore_dep = cc.find_library('uiautomationcore', + required: host_system == 'windows') +runtimeobject_dep = cc.find_library('runtimeobject', + required: host_system == 'windows') +propsys_dep = cc.find_library('propsys', + required: host_system == 'windows') + +library_dependencies_sole = [] +library_dependencies = library_dependencies_sole +private_dependencies = [] +other_library_dependencies = [] + +target = get_option('triplet') +target_arg = [] + +toolchain_arg = [] +toolchain_ver = get_option('rustc-version') + +check_version = false +# Check toolchain_ver if supplied, if in the form of a version +# We assume to continue if a stable, nightly or beta or custom toolchain is specified +if toolchain_ver != '' + if host_system != 'windows' + warning('\'rustc-version\' option currently only supported for Windows') + endif + check_version_script = find_program('meson/check-is-version-string.py', native: true) + is_version_string_check = run_command( + [check_version_script, '--string', toolchain_ver], + capture: true, + check: true + ) + check_version = is_version_string_check.stdout().split()[0] == 'check' + if check_version + if not toolchain_ver.version_compare('>=@0@'.format(msrv)) + error('Specified Rust toolchain version @0@ is less than @1@'.format(toolchain_ver, msrv)) + endif + endif +endif + +# Ideally, cc.get_argument_syntax() == 'msvc' should +# cover this, but 'clang' can mean GCC or MSVC-style +# depending on the env and/or flags on Windows +is_msvc_style = cc.get_argument_syntax() == 'msvc' or cc.get_define('_MSC_VER') != '' + +if target != '' + target_arg += ['--target', target] +endif + +if host_system == 'windows' + query_rustc_harness = find_program('meson/query-rustc.py', native: true, required: get_option('default_library') != 'shared') + + rustc_query_args = [ + query_rustc_harness, + rustc, + ] + + # First deduce the target that is to be used for the build, based on Meson build settings + host_cpu_family = host_machine.cpu_family() + rustc_toolchain_cpu = host_cpu_family == 'x86' ? 'i686' : host_cpu_family + if is_msvc_style + rustc_toolchain_cc = 'msvc' + elif cc.get_id() == 'clang' + # https://github.com/msys2/MINGW-packages/issues/13388 + is_msys2 = cc.get_define('__MINGW32__') == '1' and host_machine.cpu_family() != 'aarch64' and host_machine.system() in ['windows', 'cygwin'] + rustc_toolchain_cc = is_msys2 ? 'gnu' : 'gnullvm' + else + rustc_toolchain_cc = 'gnu' + endif + rustc_target = '@0@-pc-windows-@1@'.format(rustc_toolchain_cpu, rustc_toolchain_cc) + + if toolchain_ver != '' + build_triplet_arg = [] + if target_arg == [] + target_arg += ['--target', rustc_target] + endif + + # If doing a cross build, with '-Drustc-version=...' we must find the native toolchain on the build + # machine with its arch triplet that is to be used for building against the target, as Cargo will + # require this in its command line + if meson.is_cross_build() + build_cpu_family = build_machine.cpu_family() + rustc_build_toolchain_cpu = build_cpu_family == 'x86' ? 'i686' : build_cpu_family + rustc_build_triplet = '@0@-pc-windows-@1@'.format(rustc_build_toolchain_cpu, rustc_toolchain_cc) + build_triplet_arg += ['--build-triplet', rustc_build_triplet] + endif + + # If a version number is used, also check against the actual release that is depicted + # by the currently installed 'stable' toolchain, and use the stable toolchain if the requested + # version matches the installed 'stable' toolchain + if check_version + stable_toolchain_arg = ['--toolchain-version', 'stable'] + + stable_actual_version = run_command( + rustc_query_args + ['--query=stable-actual-version'] + stable_toolchain_arg + target_arg + build_triplet_arg, + capture: true, + check: true + ) + if stable_actual_version.stderr() != '' + error('error occurred when querying stable toolchain: @0@'.format(default_host.stderr().split()[0])) + endif + stable_version = stable_actual_version.stdout().split()[0] + if stable_version == toolchain_ver + toolchain_arg += stable_toolchain_arg + endif + endif + if toolchain_arg == [] + toolchain_arg += ['--toolchain-version', toolchain_ver] + endif + toolchain_arg += toolchain_arg + build_triplet_arg + endif + + if target_arg == [] + default_host = run_command( + rustc_query_args + ['--query=default-host-toolchain'] + toolchain_arg, + capture: true, + check: true + ) + if default_host.stderr() != '' + error('error occurred when querying default toolchain: @0@'.format(default_host.stderr().split()[0])) + endif + default_rustc_toolchain = default_host.stdout().split()[0] + + # If the default Rust target triplet does not match the triplet that we want to build for + # pass in a --target argument to RustC/Cargo that best matches what we are building for, + # if we didn't use -Dtriplet=... in the Meson setup line. Do the same if a toolchain version + # is requested + if default_rustc_toolchain != rustc_target + target_arg += ['--target', rustc_target] + endif + endif + + rustc_query_native_static_libs_args = rustc_query_args + if target_arg != [] + rustc_query_native_static_libs_args += target_arg + endif + if toolchain_arg != [] + rustc_query_native_static_libs_args += toolchain_arg + endif + rustc_query_native_static_libs_args += ['--query=native-static-libs'] + + native_libs = run_command( + rustc_query_native_static_libs_args, + capture: true, + check: true + ) + + if native_libs.stderr() != '' + error(native_libs.stderr()) + endif + + foreach i: native_libs.stdout().split() + if i != 'msvcrt' + private_dependencies += cc.find_library(i, required: get_option('default_library') != 'shared') + endif + endforeach +endif + +private_dependencies += [m_dep, appkit_dep, uiautomationcore_dep, runtimeobject_dep, propsys_dep] +library_dependencies += other_library_dependencies +library_dependencies += private_dependencies + +cargo_toml = meson.project_source_root() / 'Cargo.toml' + +project_version_args = [ + '--cargo', cargo.full_path(), + '--manifest-path', cargo_toml, +] +project_version_result = run_command( + [project_version_script, project_version_args], + capture: true, + check: true +) +project_version = project_version_result.stdout().strip() +version_parts = project_version.split('.') +if version_parts[0] == '0' + api_version = '@0@.@1@'.format(version_parts[0], version_parts[1]) +else + api_version = version_parts[0] +endif + +accesskit_c_lib_name = 'accesskit-c-@0@'.format(api_version) + +includeinc = include_directories('include') + +# Set the suffixes up +if host_system == 'windows' + lib_prefix = is_msvc_style ? '' : 'lib' + ext_dynamic = 'dll' + ext_static = is_msvc_style ? 'lib' : 'a' + ext_exe = '.exe' +elif host_system in ['darwin', 'ios'] + lib_prefix = 'lib' + ext_dynamic = 'dylib' + ext_static = 'a' + ext_exe = '' +else + lib_prefix = 'lib' + ext_dynamic = 'so' + ext_static = 'a' + ext_exe = '' +endif + +cargo_wrapper_args = [ + '--cargo', cargo.full_path(), + '--manifest-path', cargo_toml, + '--project-build-root', meson.project_build_root(), +] + +if not get_option('debug') or \ + (is_msvc_style and get_option('buildtype') == 'debugoptimized') + cargo_wrapper_args += ['--release'] +endif + +if target_arg != [] + cargo_wrapper_args += target_arg +endif +if toolchain_arg != [] + cargo_wrapper_args += toolchain_arg +endif + +includes = files( + 'include/accesskit.h' +) + +install_headers( + includes, + subdir: '@0@'.format(accesskit_c_lib_name), +) + +library_sources = files( + 'Cargo.lock', + 'Cargo.toml', + 'src/common.rs', + 'src/geometry.rs', + 'src/lib.rs', + 'src/macos.rs', + 'src/unix.rs', + 'src/windows.rs', +) + +rust_artifacts = custom_target( + 'accesskit-c', + build_by_default: true, + output: '@0@accesskit.@1@'.format(lib_prefix, ext_static), + console: true, + depend_files: library_sources, + command: [ + cargo_wrapper, + cargo_wrapper_args, + '--command=cbuild', + '--current-build-dir', '@OUTDIR@', + '--current-source-dir', meson.current_source_dir(), + '--extension', ext_static, + ], +) + +accesskit_c_lib_internal = rust_artifacts[0] + +makedef_args = [ + makedef, + '--regex', + '^accesskit_.', +] + +if host_system in ['darwin', 'ios'] + makedef_args += ['--os', 'darwin'] +elif host_system in ['windows', 'cygwin'] + makedef_args += ['--os', 'win'] +else + makedef_args += ['--os', 'linux'] +endif + +if cc.symbols_have_underscore_prefix() + makedef_args += ['--prefix', '_'] +else + makedef_args += ['--prefix', ''] +endif + +makedef_tool_args = [] + +if is_msvc_style + dumpbin = find_program('dumpbin') + makedef_tool_args += ['--dumpbin', dumpbin] +else + nm = find_program('llvm-nm', required: false) + if not nm.found() + if host_system in ['darwin', 'ios'] + warning('llvm-nm not found, you may experience problems when creating the shared libaccesskit-c.') + warning('Please install the llvm-tools component through rustup, or point Meson to an existing LLVM installation.') + endif + nm = find_program('nm') + endif + makedef_tool_args += ['--nm', nm] +endif + +symbol_list_target = custom_target( + 'accesskit-c.def', + command: [makedef_args, makedef_tool_args, '@INPUT@'], + input: accesskit_c_lib_internal, + output: 'accesskit-c.def', + capture: true, +) + +symbol_list = symbol_list_target[0] + +if host_system in ['darwin', 'ios'] + vflags = ['-Wl,-exported_symbols_list,@0@'.format(symbol_list_target.full_path())] +elif host_system == 'windows' + vflags = [] +else + vflags = ['-Wl,--version-script,@0@'.format(symbol_list_target.full_path())] +endif + +# This is not strictly needed, but since we are telling Cargo to build a staticlib, it puts in +# all of Rust's standard library and code from dependencies even when it is not needed. +# With the following, we shrink the final .so size. +# +# Also check for -Bsymbolic-functions linker flag used to avoid +# intra-library PLT jumps, if available. +strip_link_args = cc.get_supported_link_arguments( + '-Wl,-dead_strip', + '-Wl,--gc-sections', + '-Wl,-Bsymbolic-functions', +) + +link_args = vflags + strip_link_args + +# Some systems, reportedly OpenBSD and macOS, refuse +# to create libraries without any object files. Compiling +# this file, and adding its object file to the library, +# will prevent the library from being empty. +if cc.has_function_attribute('unused') + accesskit_c_dummy = configure_file( + command: [ + python, + '-c', + 'print("static int __attribute__((unused)) __accesskit_c_dummy;")' + ], + capture: true, + output: '_accesskit_c_dummy.c' + ) +else + accesskit_c_dummy = configure_file( + command: [ + python, + '-c', + 'print("static int __accesskit_c_dummy; int dummy(void) { return __accesskit_c_dummy; }")' + ], + capture: true, + output: '_accesskit_c_dummy.c' + ) +endif + +if get_option('default_library') in ['shared', 'both'] + if host_system == 'windows' + accesskit_c_shared_lib = shared_library( + accesskit_c_lib_name, + accesskit_c_dummy, + link_with: accesskit_c_lib_internal, + link_args: link_args, + link_depends: symbol_list, + dependencies: library_dependencies, + include_directories: [includeinc], + vs_module_defs: symbol_list, + install: true, + ) + else + accesskit_c_shared_lib = shared_library( + accesskit_c_lib_name, + accesskit_c_dummy, + link_whole: accesskit_c_lib_internal, + link_args: link_args, + link_depends: symbol_list, + dependencies: library_dependencies, + include_directories: [includeinc], + vs_module_defs: symbol_list, + install: true, + version: project_version, + ) + endif + if get_option('default_library') == 'shared' + accesskit_c_lib = accesskit_c_shared_lib + endif +endif +if get_option('default_library') in ['static', 'both'] + # The static library must be manually generated so that it matches Meson's + # naming convention. + accesskit_c_lib = custom_target( + 'accesskit-c-static', + input: accesskit_c_lib_internal, + output: '@0@@1@.@2@'.format(lib_prefix, accesskit_c_lib_name, 'a'), + command: [ + python, + '-c', + 'import os; import sys; import shutil; shutil.copy(sys.argv[1], sys.argv[2])', + '@INPUT0@', + '@OUTPUT0@' + ], + install: true, + install_dir: get_option('libdir'), + ) +endif + +# This is the main dependency to use for tests; it means "link to the library we just built" +accesskit_c_dep = declare_dependency( + sources: includes, + include_directories: [includeinc], + dependencies: library_dependencies, + link_with: accesskit_c_lib, +) + +meson.override_dependency(accesskit_c_lib_name, accesskit_c_dep) + +pkg = import('pkgconfig') + +# If any of the dependencies is e.g. wrap, ignore as we can't include +# them without knowing how they exposed the pkg-config module +# (if CMake, there's simply no way at all) +has_pkgconfig_dependencies = true + +foreach i : library_dependencies_sole + if i.found() and i.type_name() != 'pkgconfig' + warning('One or more dependencies are not provided by pkg-config, skipping generation of the pkg-config module.') + has_pkgconfig_dependencies = false + break + endif +endforeach + +if has_pkgconfig_dependencies + accesskit_c_pc = pkg.generate( + name: 'accesskit-c', + filebase: accesskit_c_lib_name, + version: project_version, + description: 'UI accessibility infrastructure (C API)', + libraries: [accesskit_c_lib] + other_library_dependencies, + subdirs: accesskit_c_lib_name, + requires: library_dependencies_sole, + libraries_private: private_dependencies, + ) +endif diff --git a/meson/cargo_wrapper.py b/meson/cargo_wrapper.py new file mode 100755 index 0000000..dc80ae0 --- /dev/null +++ b/meson/cargo_wrapper.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 +# Derived from the librsvg Meson build +# Copyright (c) 2024 L. E. Segovia +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see . + +from argparse import ArgumentParser +import os +from pathlib import Path +import shutil +import subprocess +import sys + +parser = ArgumentParser() + +parser.add_argument( + "--command", + required=True, + choices=["cbuild", "test", "build"], + help="Cargo command", +) + +parser.add_argument( + "--cargo", required=True, type=Path, help="Path to the cargo executable" +) + +parser.add_argument( + "--manifest-path", required=True, type=Path, help="Path to Cargo.toml" +) + +parser.add_argument( + "--current-build-dir", + required=True, + type=Path, + help="Value from meson.current_build_dir()", +) + +parser.add_argument( + "--current-source-dir", + required=True, + type=Path, + help="Value from meson.current_source_dir()", +) + +parser.add_argument( + "--project-build-root", + required=True, + type=Path, + help="Value from meson.project_build_root()", +) + +parser.add_argument( + "--toolchain-version", help="Rust Toolchain Version if needed" +) + +parser.add_argument( + "--target", help="Target triplet" +) + +parser.add_argument( + "--build-triplet", help="Build toolchain triplet (for cross builds using specific toolchain version)" +) + +parser.add_argument( + "--release", action="store_true", help="Build artifacts in release mode" +) + +parser.add_argument( + "--extension", required=True, help="filename extension for the library (so, a, dll, lib, dylib)", +) + +args = parser.parse_args() + +if args.toolchain_version is not None and args.target is None and args.build_triplet is None: + raise ValueError('--target and/or --build-triplet argument required if --toolchain-version is specified') + +if args.command == 'test': + if args.extension or args.bin: + raise ValueError('Cargo test does not take --extension or --bin') + +cargo_target_dir = Path(args.project_build_root) / "target" + +if args.target: + cargo_target_output_dir = cargo_target_dir / args.target +else: + cargo_target_output_dir = cargo_target_dir + +env = os.environ.copy() +pkg_config_path = [i for i in env.get("PKG_CONFIG_PATH", "").split(os.pathsep) if i] +pkg_config_path.insert( + 0, (Path(args.project_build_root) / "meson-uninstalled").as_posix() +) +env["PKG_CONFIG_PATH"] = os.pathsep.join(pkg_config_path) + +features = [] + +cargo_cmd = [Path(args.cargo).as_posix()] + +if args.toolchain_version is not None: + if args.build_triplet is not None: + cargo_cmd.extend(["+%s-%s" % (args.toolchain_version, args.build_triplet)]) + else: + cargo_cmd.extend(["+%s-%s" % (args.toolchain_version, args.target)]) + +if args.command == "cbuild": + cargo_cmd.extend(["rustc", "--locked"]) + library_type = "staticlib" if args.extension in ("a", "lib") else "cdylib" + cargo_cmd.extend(["--crate-type", library_type]) +elif args.command == "test": + cargo_cmd.extend(["test", "--locked", "--no-fail-fast", "--color=always"]) +else: + cargo_cmd.extend(["build", "--locked"]) + if args.bin: + cargo_cmd.extend(["--bin", args.bin]) + +cargo_cmd.extend(["--manifest-path", Path(args.manifest_path).as_posix()]) +cargo_cmd.extend(["--target-dir", cargo_target_dir.as_posix()]) + +if args.release: + buildtype = 'release' + cargo_cmd.extend(['--release']) +else: + buildtype = 'debug' + +if args.target: + cargo_cmd.extend(['--target', args.target]) + +if features: + cargo_cmd.extend(["--features", ",".join(features)]) + +if args.command == "test": + cargo_cmd.extend(["--", "--include-ignored"]) + +print(f"command: {cargo_cmd}") +subprocess.run(cargo_cmd, env=env, check=True) + +if args.command in ["cbuild", "build"]: + for f in cargo_target_dir.glob(f"**/{buildtype}/*.{args.extension}"): + shutil.copy(f, args.current_build_dir) diff --git a/meson/check-is-version-string.py b/meson/check-is-version-string.py new file mode 100644 index 0000000..395b42c --- /dev/null +++ b/meson/check-is-version-string.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# Derived from the librsvg Meson build +# Copyright (c) 2024 L. E. Segovia +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see . + +# Simple script to check whether rustc-version is to be checkedn against minimum supported rust version + +import sys +from argparse import ArgumentParser + +if __name__ == "__main__": + parser = ArgumentParser() + parser.add_argument('--string', help='String to check is a version-like string', required=True) + args = parser.parse_args() + parts = args.string.split('.') + if len(parts) != 2 and len(parts) != 3: + print('skip') + else: + for p in parts: + try: + int(p) + except ValueError: + print('skip') + sys.exit() + print('check') diff --git a/meson/makedef.py b/meson/makedef.py new file mode 100755 index 0000000..a04cba0 --- /dev/null +++ b/meson/makedef.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python3 +# Copyright (c) 2022 L. E. Segovia +# +# This file is part of the FFmpeg Meson build +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see . + +import argparse +import errno +import os +import pathlib +import re +import subprocess + + +def output(platform, symbols): + if platform == 'win': + print("EXPORTS") + print(*[f' {symbol}' for symbol in sorted(set(symbols))], sep='\n') + elif platform == 'darwin': + print(*[f'{prefix}{symbol}' for symbol in sorted(set(symbols))], sep='\n') + else: + print('{') + print(' global:') + print( + *[f' {prefix}{symbol};' for symbol in sorted(set(symbols))], sep='\n') + print(' local:') + print(' *;') + print('};') + + +if __name__ == '__main__': + arg_parser = argparse.ArgumentParser( + description='Craft the symbols exports file') + + arg_parser.add_argument('--prefix', metavar='PREFIX', + help='Prefix for extern symbols') + g = arg_parser.add_argument_group('Library parsing tool') + group = g.add_mutually_exclusive_group(required=True) + group.add_argument('--nm', metavar='NM_PATH', type=pathlib.Path, + help='If specified, runs this instead of dumpbin (MinGW)') + group.add_argument('--dumpbin', metavar='DUMPBIN_PATH', type=pathlib.Path, + help='If specified, runs this instead of nm (MSVC)') + group.add_argument( + '--list', action='store_true', help='If specified, consider FILE as an exported symbols list instead of a library') + g = arg_parser.add_argument_group('Symbol naming') + group = g.add_mutually_exclusive_group(required=True) + group.add_argument('--regex', metavar='REGEX', type=str, + nargs='+', + help='Regular expression for exported symbols') + group.add_argument('--vscript', metavar='VERSION_SCRIPT', + type=argparse.FileType('r'), help='Version script') + arg_parser.add_argument('--os', type=str, choices=('win', 'linux', 'darwin'), + default='linux', required=True, + help='Target operating system for the exports file (win = MSVC module definition file, linux = version script, darwin = exported symbols list)') + arg_parser.add_argument('libnames', metavar='FILE', type=pathlib.Path, + nargs='+', + help='Source file(s) to parse') + + args = arg_parser.parse_args() + + libnames = args.libnames + + for libname in libnames: + if not libname.exists(): + raise FileNotFoundError( + errno.ENOENT, os.strerror(errno.ENOENT), libname) + + if not args.list and len(libnames) > 1: + raise ValueError("Expect 1 filename as argument.") + + prefix = args.prefix or '' + started = 0 + regex = [] + + if args.vscript: + for line in args.vscript: + # We only care about global symbols + if re.match(r'^\s+global:', line): + started = 1 + line = re.sub(r'^\s+global: *', '', line) + else: + if re.match(r'^\s+local:', line): + started = 0 + + if started == 0: + continue + + line = line.replace(';', '') + + for exp in line.split(): + # Remove leading and trailing whitespace + regex.append(exp.strip()) + else: + regex.extend(args.regex) + + # Ensure things are compatible on Windows with Python 3.7.x + libname_path_posix = pathlib.Path(libnames[0]).as_posix() + + if args.list: + dump = [] + for libname in libnames: + syms = libname.open('r', encoding='utf-8').readlines() + # Strip whitespaces + syms = [x.strip() for x in syms] + # Exclude blank lines + syms = [x for x in syms if len(x) > 0] + dump.extend(syms) + elif args.nm is not None: + # Use eval, since NM="nm -g" + # Add -j to ensure only symbol names are output (otherwise in macOS + # a race condition can occur in the redirection) + # And use `--no-llvm-bc` in case it's /usr/bin/nm on macOS + s = subprocess.run( + [args.nm, '-U', '-g', '-j', '--no-llvm-bc', libname_path_posix], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + universal_newlines=True, + check=False, + ) + if s.returncode != 0: + # If it fails, retry without skipping LLVM bitcode (macOS flag) + s = subprocess.run( + [args.nm, '-U', '-g', '-j', libname_path_posix], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + universal_newlines=True, + check=False, + ) + if s.returncode != 0: + # -j was added only in Binutils 2.37 + s = subprocess.run( + [args.nm, '-U', '-g', libname_path_posix], + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + universal_newlines=True, + check=True, + ) + dump = s.stdout.splitlines() + # Exclude lines with ':' (object name) + dump = [x for x in dump if ":" not in x] + # Exclude blank lines + dump = [x for x in dump if len(x) > 0] + # Subst the prefix out + dump = [re.sub(f'^{prefix}', '', x) for x in dump] + else: + dump = subprocess.run([pathlib.Path(args.dumpbin).as_posix(), '-linkermember:1', libname_path_posix], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True).stdout.splitlines() + # Find the index of the first line with + # "public symbols", keep the rest + # Then the line with " Summary", + # delete it and the rest + for i, line in enumerate(dump): + if 'public symbols' in line: + start = i + elif re.match(r'\s+Summary', line): + end = i + dump = dump[start:end] + # Substitute prefix out + dump = [re.sub(fr'\s+{prefix}', ' ', x) for x in dump] + # Substitute big chonky spaces out + dump = [re.sub(r'\s+', ' ', x) for x in dump] + # Exclude blank lines + dump = [x for x in dump if len(x) > 0] + # Take only the *second* field (split by spaces) + # Python's split excludes whitespace at the beginning + dump = [x.split()[1] for x in dump] + + symbols = [] + for exp in regex: + for i in dump: + if re.match(exp, i): + symbols.append(i) + + output(args.os, symbols) diff --git a/meson/project_version.py b/meson/project_version.py new file mode 100755 index 0000000..0170f6e --- /dev/null +++ b/meson/project_version.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +# Derived from the librsvg Meson build +# Copyright (c) 2024 L. E. Segovia +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see . + +from argparse import ArgumentParser +import json +import os +from pathlib import Path +import shutil +import subprocess +import sys + +parser = ArgumentParser() + +parser.add_argument( + "--cargo", required=True, type=Path, help="Path to the cargo executable" +) + +parser.add_argument( + "--manifest-path", required=True, type=Path, help="Path to Cargo.toml" +) + +parser.add_argument( + "--toolchain-version", help="Rust Toolchain Version if needed" +) + +parser.add_argument( + "--target", help="Target triplet" +) + +parser.add_argument( + "--build-triplet", help="Build toolchain triplet (for cross builds using specific toolchain version)" +) + +args = parser.parse_args() + +if args.toolchain_version is not None and args.target is None and args.build_triplet is None: + raise ValueError('--target and/or --build-triplet argument required if --toolchain-version is specified') + +cargo_cmd = [Path(args.cargo).as_posix()] + +if args.toolchain_version is not None: + if args.build_triplet is not None: + cargo_cmd.extend(["+%s-%s" % (args.toolchain_version, args.build_triplet)]) + else: + cargo_cmd.extend(["+%s-%s" % (args.toolchain_version, args.target)]) + +cargo_cmd.append("read-manifest") +cargo_cmd.extend(["--manifest-path", Path(args.manifest_path).as_posix()]) + +result = subprocess.run(cargo_cmd, capture_output=True, check=True) +manifest = json.loads(result.stdout) +print(manifest["version"]) diff --git a/meson/query-rustc.py b/meson/query-rustc.py new file mode 100755 index 0000000..4084535 --- /dev/null +++ b/meson/query-rustc.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +# Derived from the librsvg Meson build +# Copyright (c) 2024 L. E. Segovia +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see . + +from argparse import ArgumentParser +from pathlib import Path +import os +import re +import subprocess +import sys +import tempfile + +parser = ArgumentParser() + +parser.add_argument("RUSTC", type=Path, help="Path to rustc") +parser.add_argument("--query", action="store", + choices=['native-static-libs', 'default-host-toolchain', 'stable-actual-version'], + help="Item to query from RustC ['native-static-libs', 'default-host-toolchain', 'stable-actual-version']", + required=True) +parser.add_argument("--toolchain-version", action="store", + help="Rust Toolchain Version (if needed)") +parser.add_argument("--target", help="Target triplet") +parser.add_argument("--build-triplet", help="Build machine triplet (for cross builds using specific toolchain version)") + +def removeprefix_fallback(s, pfx): + if sys.version_info > (3, 9): + return s.removeprefix(pfx) + elif s.startswith(pfx): + return s[len(pfx):] + else: + return s + +def removesuffix_fallback(s, sfx): + if sys.version_info > (3, 9): + return s.removesuffix(sfx) + elif s.endswith(sfx): + return s[:-len(sfx)] + else: + return s + +def retrieve_native_static_libs_from_output(output): + if re.match(r'^error[:|\[]', output): + print(output, file=sys.stderr) + sys.exit() + + for i in output.strip().splitlines(): + match = re.match(r".+native-static-libs: (.+)", i) + if match: + libs = match.group(1).split() + libs = [removesuffix_fallback(lib, ".lib") for lib in libs] # msvc + libs = [removeprefix_fallback(lib, "-l") for lib in libs] # msys2 + print( + " ".join( + set( + libs + ) + ) + ) + +# Get the default target host or actual version of toolchain +def retrive_version_info(output, query): + for i in output.strip().splitlines(): + match = re.match(r"%s: (.+)" % query, i) + if match: + return match.group(1) + +if __name__ == "__main__": + args = parser.parse_args() + query = args.query + query_arg = None + rustc_cmd = [Path(args.RUSTC).as_posix()] + + if args.toolchain_version is not None: + if args.target is None and args.build_triplet is None: + raise ValueError('--target or --build-triplet argument required if --toolchain-version is used') + if args.build_triplet is not None: + rustc_cmd.extend(['+%s-%s' % (args.toolchain_version, args.build_triplet)]) + else: + rustc_cmd.extend(['+%s-%s' % (args.toolchain_version, args.target)]) + + if query == 'native-static-libs': + query_arg = ['--print=%s' % query] + else: + query_arg = ['--version', '--verbose'] + rustc_cmd.extend(query_arg) + if args.target: + rustc_cmd.extend(['--target', args.target]) + + fd, dummy_out = tempfile.mkstemp() + os.close(fd) + try: + # We need these for '--print=native-static-libs' on Windows + if query == 'native-static-libs': + rustc_cmd.extend(['--crate-type', 'staticlib']) + rustc_cmd.append(os.devnull) + rustc_cmd.extend(['-o', dummy_out]) + query_results = subprocess.run( + rustc_cmd, + capture_output=True, + text=True, + ) + finally: + os.unlink(dummy_out) + + if query == 'native-static-libs': + retrieve_native_static_libs_from_output(query_results.stderr) + elif query == 'default-host-toolchain' or query == 'stable-actual-version': + if query_results.stderr == '': + if query == 'default-host-toolchain': + result = retrive_version_info(query_results.stdout, 'host') + else: + result = retrive_version_info(query_results.stdout, 'release') + print(result) + else: + print(query_results.stderr, file=sys.stderr) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..301b954 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,25 @@ +# Derived from the librsvg Meson build +# Copyright (c) 2024 L. E. Segovia +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see . + +option('triplet', + type: 'string', + value: '', + description : 'Rust target triplet (if needed)') + +option('rustc-version', + type: 'string', + value: '', + description: 'Installed RustC version to use (if needed; currently only supported for Windows builds)')