├── .github └── workflows │ └── build.yml ├── .gitignore ├── Changes ├── LICENSE ├── MANIFEST.SKIP ├── Makefile.PL ├── README.md ├── cpanfile ├── lib └── Perl │ └── Dist │ └── APPerl.pm ├── script └── apperlm ├── share ├── 5.36-cosmo-apperl.patch ├── 5.36-cosmo.patch └── 5.36-cosmo3.patch ├── t └── tests.t └── xt └── author ├── build.t └── pod_linkcheck.t /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | 2 | # GitHub Actions CI script for Perl-Dist-APPerl 3 | # (C) 2022 Gavin Hayes 4 | 5 | name: Build Actually Portable Perl 6 | on: [ push, pull_request ] 7 | 8 | jobs: 9 | build-linux: 10 | name: Build Perl-Dist-APPerl 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Fetch repo 14 | uses: actions/checkout@v3 15 | with: 16 | path: 'Perl-Dist-APPerl' 17 | - name: Install Perl 18 | uses: shogo82148/actions-setup-perl@v1 19 | with: 20 | perl-version: '5.36' 21 | install-modules-with: cpanm 22 | install-modules: File::ShareDir::Install 23 | - name: Test in-tree 24 | run: | 25 | cd Perl-Dist-APPerl 26 | prove -lv t 27 | - name: Build Perl-Dist-APPerl release 28 | run: | 29 | cd Perl-Dist-APPerl 30 | perl Makefile.PL 31 | make manifest 32 | make dist 33 | mv Perl-Dist-APPerl-v*.tar.gz ../ 34 | - name: Upload build artifacts 35 | uses: actions/upload-artifact@v3 36 | with: 37 | name: cpan 38 | if-no-files-found: error 39 | path: Perl-Dist-APPerl-v*.tar.gz 40 | 41 | build-apperl: 42 | name: Build perl.com 43 | runs-on: ubuntu-latest 44 | needs: build-linux 45 | strategy: 46 | matrix: 47 | config: [full, small, full-vista, small-vista] 48 | steps: 49 | - name: Fetch build artifacts 50 | uses: actions/download-artifact@v3 51 | - name: prepare for installing module 52 | run: | 53 | mv cpan/Perl-Dist-APPerl-v*.tar.gz Perl-Dist-APPerl.tar.gz 54 | - name: Install Perl 55 | uses: shogo82148/actions-setup-perl@v1 56 | with: 57 | perl-version: '5.36' 58 | install-modules-with: cpanm 59 | install-modules: Perl-Dist-APPerl.tar.gz 60 | - name: Load config 61 | run: | 62 | echo "PERL_ID=$(apperlm get-config-key ${{ matrix.config }} perl_id)" >> $GITHUB_ENV 63 | echo "COSMO_ID=$(apperlm get-config-key ${{ matrix.config }} cosmo_id)" >> $GITHUB_ENV 64 | echo "DEST_BIN=$(apperlm get-config-key ${{ matrix.config }} dest)" >> $GITHUB_ENV 65 | echo "REL_NAME=APPerl-$(perl -MPerl::Dist::APPerl -e 'print $Perl::Dist::APPerl::VERSION')-${{ matrix.config }}.zip" >> $GITHUB_ENV 66 | - name: Fetch Perl fork 67 | uses: actions/checkout@v3 68 | with: 69 | repository: 'G4Vi/perl5' 70 | ref: ${{ env.PERL_ID }} 71 | path: 'perl5' 72 | - name: Fetch cosmopolitan 73 | uses: actions/checkout@v3 74 | with: 75 | repository: 'jart/cosmopolitan' 76 | ref: ${{ env.COSMO_ID }} 77 | path: 'cosmopolitan' 78 | - name: support ape bins 79 | run: sudo sh -c "echo ':APE:M::MZqFpD::/bin/sh:' >/proc/sys/fs/binfmt_misc/register" 80 | - name: Configure and Build perl.com 81 | env: 82 | CF_BY: ${{ secrets.CF_BY }} 83 | CF_EMAIL: ${{ secrets.CF_EMAIL }} 84 | run: | 85 | ls -la 86 | apperlm install-build-deps -p perl5 -c cosmopolitan 87 | apperlm init --name ${{ matrix.config }} 88 | apperlm list 89 | apperlm configure -Dcf_by="$CF_BY" -Dcf_email="$CF_EMAIL" 90 | apperlm build 91 | zip -r ${{ env.REL_NAME }} ${{ env.DEST_BIN }} ${{ env.DEST_BIN }}.dbg 92 | - name: Upload build artifacts 93 | uses: actions/upload-artifact@v3 94 | with: 95 | name: ${{ matrix.config }} 96 | if-no-files-found: error 97 | path: | 98 | ${{ env.DEST_BIN }} 99 | ${{ env.DEST_BIN }}.dbg 100 | ${{ env.REL_NAME }} 101 | 102 | test-Perl-Dist-APPerl: 103 | name: test Perl-Dist-APPerl 104 | runs-on: ubuntu-latest 105 | needs: build-apperl 106 | strategy: 107 | matrix: 108 | version: ['5.10', '5.36'] 109 | steps: 110 | - name: Fetch repo 111 | uses: actions/checkout@v3 112 | with: 113 | path: 'Perl-Dist-APPerl' 114 | - name: Install Perl 115 | uses: shogo82148/actions-setup-perl@v1 116 | with: 117 | perl-version: ${{ matrix.version }} 118 | install-modules-with: cpanm 119 | install-modules: B::Keywords HTTP::Tiny Test::Pod::LinkCheck::Lite 120 | - name: download build artifacts 121 | uses: actions/download-artifact@v3 122 | - name: Setup for tests 123 | run: | 124 | cd Perl-Dist-APPerl 125 | cpanm --installdeps --notest . 126 | mv ../full/perl.com* ./ 127 | chmod +x perl.com 128 | mv ../small/perl-small.com* ./ 129 | mv ../full-vista/perl-vista.com* ./ 130 | mv ../small-vista/perl-small-vista.com* ./ 131 | sudo sh -c "echo ':APE:M::MZqFpD::/bin/sh:' >/proc/sys/fs/binfmt_misc/register" 132 | - name: Run tests 133 | run: | 134 | cd Perl-Dist-APPerl 135 | perl Makefile.PL 136 | make 137 | make authortest 138 | - name: Archive CPAN logs 139 | if: ${{ failure() }} 140 | uses: actions/upload-artifact@v3 141 | with: 142 | name: cpan_log 143 | path: /home/runner/.cpanm/work/*/build.log 144 | 145 | test-nobuild-builds: 146 | name: Test building nobuild configs 147 | needs: build-apperl 148 | strategy: 149 | matrix: 150 | os: [ubuntu-latest] #, windows-latest] 151 | runs-on: ${{ matrix.os }} 152 | steps: 153 | - name: Fetch build artifacts 154 | uses: actions/download-artifact@v3 155 | - name: support ape bins 156 | run: sudo sh -c "echo ':APE:M::MZqFpD::/bin/sh:' >/proc/sys/fs/binfmt_misc/register" 157 | - name: Try nobuild build 158 | run: | 159 | mkdir src 160 | cp full/perl.com src/ 161 | chmod +x src/perl.com 162 | src/perl.com /zip/bin/apperlm list 163 | 164 | create-release: 165 | name: Create release 166 | runs-on: ubuntu-latest 167 | needs: [ build-linux, build-apperl, test-Perl-Dist-APPerl, test-nobuild-builds ] 168 | steps: 169 | - name: Fetch build artifacts 170 | if: ${{ github.ref_type == 'tag' }} 171 | uses: actions/download-artifact@v3 172 | - name: Build binary amalgamation for uploading to microsoft 173 | if: ${{ github.ref_type == 'tag' }} 174 | run: | 175 | sudo sh -c "echo ':APE:M::MZqFpD::/bin/sh:' >/proc/sys/fs/binfmt_misc/register" 176 | chmod +x full/perl.com 177 | REL_NAME=APPerl-$(full/perl.com -MPerl::Dist::APPerl -e 'print $Perl::Dist::APPerl::VERSION')-all.zip 178 | zip -r $REL_NAME */*.com* 179 | - name: Publish release 180 | if: ${{ github.ref_type == 'tag' }} 181 | uses: softprops/action-gh-release@v1 182 | with: 183 | fail_on_unmatched_files: true 184 | draft: true 185 | files: | 186 | cpan/Perl-Dist-APPerl-v*.tar.gz 187 | full/* 188 | small/* 189 | full-vista/* 190 | small-vista/* 191 | APPerl-*-all.zip 192 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | MANIFEST 2 | .apperl 3 | .vscode -------------------------------------------------------------------------------- /Changes: -------------------------------------------------------------------------------- 1 | Revision history for Perl-Dist-APPerl 2 | v0.6.1 2024-08-29 3 | Fix bootstrapped builds by opening pipe to `patch` stdin instead 4 | of redirecting stdin to file. (redirecting to /zip is 5 | impossible) 6 | If output files exist rename them with `.old` to avoid bus error 7 | when one of the output files is the same as the running 8 | executable. 9 | 10 | v0.6.0 2024-05-27 11 | Add building with modern Cosmopolitan Libc with cosmocc 3.3.10 12 | cosmocc automatically installs itself making running 13 | `apperlm install-build-deps` unnecessary 14 | Add download and building from Perl tarballs. 15 | Add patch loading system so Perl changes can be maintained from 16 | this repo. Can locate "share" dir even when used from APPerl. 17 | Fix install_modules not linking all extensions. 18 | Devel::PPort and DynaLoader weren't being linked in 19 | This caused Cwd.pm to fail to load its XS 20 | Improve apperlm list 21 | Include ErrnoRuntime in small builds 22 | Deprecate vista builds 23 | Without cosmocc being avaiable on the port, they have to be 24 | maintained essentially seperately. 25 | Remove most of the versioned configs, they were far behind the 26 | rolling release / unnamed builds and often changed with them. 27 | Make $^X more reliable by using Cosmos's GetProgramExecutableName 28 | Set $Config{perlpath} to $^X (GH#6) 29 | Fix APPERL_DEFAULT_SCRIPT search by including nul in string. 30 | 31 | v0.5.0 2024-03-21 32 | Revert `full` and `small` targets with cosmo 3.0.2 33 | Base `full` and `small` (with vista) targets off of perl 5.36.3 34 | 35 | v0.4.0 2023-11-17 36 | Make tests more Windows compatible 37 | Build `full` and `small` targets with cosmo 3.0.2 38 | Base `full` and `small` targets off of perl 5.36.1 39 | Build `vista` targets with cosmo fea68b1 40 | 41 | v0.3.0 2023-01-29 42 | Added running scripts from APPERL_SCRIPTNAME environment 43 | variable 44 | Added setting fallback script to run if argv[0] script 45 | execution fails, set `default_script` in your config 46 | Added installing CPAN distributions from tarball or directory 47 | on disk via "install_modules" in project config. 48 | full, small, and vista variant configs: 49 | Removed version from privlib archlib sitelib sitearch 50 | Updated Cosmopolitan source 51 | Updated Perl source 52 | Added dbg config: gdb not working for me, YYMV 53 | Better support --ftrace by outputting .com.dbg instead of elf 54 | Updated docs with new info. 55 | 56 | v0.2.1 2022-12-03 57 | Remove dependency on Env module. 58 | 59 | v0.2.0 2022-11-27 60 | Enable cross-platform builds of `nobuild` configs. Switch 61 | remaining `mv`, `cp`, `rm` shell commands to use their perl 62 | equivalents. Add workaround to `apperlm` for running Info-ZIP 63 | on Windows from APPerl. 64 | 65 | v0.1.1 2022-11-17 66 | Fix 5.10 support and broken pod link, thanks to MJGARDNER 67 | (GH#1). 68 | 69 | v0.1.0 2022-11-13 70 | Fix issues with Time-HiRes Configure. Update to Cosmopolitan 71 | Libc v2.2 . Pin Perl version to configs. 72 | 73 | v0.0.4 2022-10-15 74 | Make Actions release binaries executable 75 | 76 | v0.0.3 2022-10-14 77 | Bumped cosmopolitan versions. Add category to apperlm list. Add 78 | leading '-' support to config parsing to remove items from an 79 | existing set. 80 | 81 | v0.0.2 2022-10-10 82 | Add small builds to actions, rewrite acknowledgements. 83 | 84 | v0.0.1 2022-10-10 85 | First packaged version, released on an unsuspecting world. 86 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Terms of the Perl programming language system itself 2 | 3 | a) the GNU General Public License as published by the Free 4 | Software Foundation; either version 1, or (at your option) any 5 | later version, or 6 | b) the "Artistic License" 7 | 8 | --- The GNU General Public License, Version 1, February 1989 --- 9 | 10 | This software is Copyright (c) 2021-2024 by Gavin Hayes. 11 | 12 | This is free software, licensed under: 13 | 14 | The GNU General Public License, Version 1, February 1989 15 | 16 | GNU GENERAL PUBLIC LICENSE 17 | Version 1, February 1989 18 | 19 | Copyright (C) 1989 Free Software Foundation, Inc. 20 | 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 | 22 | Everyone is permitted to copy and distribute verbatim copies 23 | of this license document, but changing it is not allowed. 24 | 25 | Preamble 26 | 27 | The license agreements of most software companies try to keep users 28 | at the mercy of those companies. By contrast, our General Public 29 | License is intended to guarantee your freedom to share and change free 30 | software--to make sure the software is free for all its users. The 31 | General Public License applies to the Free Software Foundation's 32 | software and to any other program whose authors commit to using it. 33 | You can use it for your programs, too. 34 | 35 | When we speak of free software, we are referring to freedom, not 36 | price. Specifically, the General Public License is designed to make 37 | sure that you have the freedom to give away or sell copies of free 38 | software, that you receive source code or can get it if you want it, 39 | that you can change the software or use pieces of it in new free 40 | programs; and that you know you can do these things. 41 | 42 | To protect your rights, we need to make restrictions that forbid 43 | anyone to deny you these rights or to ask you to surrender the rights. 44 | These restrictions translate to certain responsibilities for you if you 45 | distribute copies of the software, or if you modify it. 46 | 47 | For example, if you distribute copies of a such a program, whether 48 | gratis or for a fee, you must give the recipients all the rights that 49 | you have. You must make sure that they, too, receive or can get the 50 | source code. And you must tell them their rights. 51 | 52 | We protect your rights with two steps: (1) copyright the software, and 53 | (2) offer you this license which gives you legal permission to copy, 54 | distribute and/or modify the software. 55 | 56 | Also, for each author's protection and ours, we want to make certain 57 | that everyone understands that there is no warranty for this free 58 | software. If the software is modified by someone else and passed on, we 59 | want its recipients to know that what they have is not the original, so 60 | that any problems introduced by others will not reflect on the original 61 | authors' reputations. 62 | 63 | The precise terms and conditions for copying, distribution and 64 | modification follow. 65 | 66 | GNU GENERAL PUBLIC LICENSE 67 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 68 | 69 | 0. This License Agreement applies to any program or other work which 70 | contains a notice placed by the copyright holder saying it may be 71 | distributed under the terms of this General Public License. The 72 | "Program", below, refers to any such program or work, and a "work based 73 | on the Program" means either the Program or any work containing the 74 | Program or a portion of it, either verbatim or with modifications. Each 75 | licensee is addressed as "you". 76 | 77 | 1. You may copy and distribute verbatim copies of the Program's source 78 | code as you receive it, in any medium, provided that you conspicuously and 79 | appropriately publish on each copy an appropriate copyright notice and 80 | disclaimer of warranty; keep intact all the notices that refer to this 81 | General Public License and to the absence of any warranty; and give any 82 | other recipients of the Program a copy of this General Public License 83 | along with the Program. You may charge a fee for the physical act of 84 | transferring a copy. 85 | 86 | 2. You may modify your copy or copies of the Program or any portion of 87 | it, and copy and distribute such modifications under the terms of Paragraph 88 | 1 above, provided that you also do the following: 89 | 90 | a) cause the modified files to carry prominent notices stating that 91 | you changed the files and the date of any change; and 92 | 93 | b) cause the whole of any work that you distribute or publish, that 94 | in whole or in part contains the Program or any part thereof, either 95 | with or without modifications, to be licensed at no charge to all 96 | third parties under the terms of this General Public License (except 97 | that you may choose to grant warranty protection to some or all 98 | third parties, at your option). 99 | 100 | c) If the modified program normally reads commands interactively when 101 | run, you must cause it, when started running for such interactive use 102 | in the simplest and most usual way, to print or display an 103 | announcement including an appropriate copyright notice and a notice 104 | that there is no warranty (or else, saying that you provide a 105 | warranty) and that users may redistribute the program under these 106 | conditions, and telling the user how to view a copy of this General 107 | Public License. 108 | 109 | d) You may charge a fee for the physical act of transferring a 110 | copy, and you may at your option offer warranty protection in 111 | exchange for a fee. 112 | 113 | Mere aggregation of another independent work with the Program (or its 114 | derivative) on a volume of a storage or distribution medium does not bring 115 | the other work under the scope of these terms. 116 | 117 | 3. You may copy and distribute the Program (or a portion or derivative of 118 | it, under Paragraph 2) in object code or executable form under the terms of 119 | Paragraphs 1 and 2 above provided that you also do one of the following: 120 | 121 | a) accompany it with the complete corresponding machine-readable 122 | source code, which must be distributed under the terms of 123 | Paragraphs 1 and 2 above; or, 124 | 125 | b) accompany it with a written offer, valid for at least three 126 | years, to give any third party free (except for a nominal charge 127 | for the cost of distribution) a complete machine-readable copy of the 128 | corresponding source code, to be distributed under the terms of 129 | Paragraphs 1 and 2 above; or, 130 | 131 | c) accompany it with the information you received as to where the 132 | corresponding source code may be obtained. (This alternative is 133 | allowed only for noncommercial distribution and only if you 134 | received the program in object code or executable form alone.) 135 | 136 | Source code for a work means the preferred form of the work for making 137 | modifications to it. For an executable file, complete source code means 138 | all the source code for all modules it contains; but, as a special 139 | exception, it need not include source code for modules which are standard 140 | libraries that accompany the operating system on which the executable 141 | file runs, or for standard header files or definitions files that 142 | accompany that operating system. 143 | 144 | 4. You may not copy, modify, sublicense, distribute or transfer the 145 | Program except as expressly provided under this General Public License. 146 | Any attempt otherwise to copy, modify, sublicense, distribute or transfer 147 | the Program is void, and will automatically terminate your rights to use 148 | the Program under this License. However, parties who have received 149 | copies, or rights to use copies, from you under this General Public 150 | License will not have their licenses terminated so long as such parties 151 | remain in full compliance. 152 | 153 | 5. By copying, distributing or modifying the Program (or any work based 154 | on the Program) you indicate your acceptance of this license to do so, 155 | and all its terms and conditions. 156 | 157 | 6. Each time you redistribute the Program (or any work based on the 158 | Program), the recipient automatically receives a license from the original 159 | licensor to copy, distribute or modify the Program subject to these 160 | terms and conditions. You may not impose any further restrictions on the 161 | recipients' exercise of the rights granted herein. 162 | 163 | 7. The Free Software Foundation may publish revised and/or new versions 164 | of the General Public License from time to time. Such new versions will 165 | be similar in spirit to the present version, but may differ in detail to 166 | address new problems or concerns. 167 | 168 | Each version is given a distinguishing version number. If the Program 169 | specifies a version number of the license which applies to it and "any 170 | later version", you have the option of following the terms and conditions 171 | either of that version or of any later version published by the Free 172 | Software Foundation. If the Program does not specify a version number of 173 | the license, you may choose any version ever published by the Free Software 174 | Foundation. 175 | 176 | 8. If you wish to incorporate parts of the Program into other free 177 | programs whose distribution conditions are different, write to the author 178 | to ask for permission. For software which is copyrighted by the Free 179 | Software Foundation, write to the Free Software Foundation; we sometimes 180 | make exceptions for this. Our decision will be guided by the two goals 181 | of preserving the free status of all derivatives of our free software and 182 | of promoting the sharing and reuse of software generally. 183 | 184 | NO WARRANTY 185 | 186 | 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 187 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 188 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 189 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 190 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 191 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 192 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 193 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 194 | REPAIR OR CORRECTION. 195 | 196 | 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 197 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 198 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 199 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 200 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 201 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 202 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 203 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 204 | POSSIBILITY OF SUCH DAMAGES. 205 | 206 | END OF TERMS AND CONDITIONS 207 | 208 | Appendix: How to Apply These Terms to Your New Programs 209 | 210 | If you develop a new program, and you want it to be of the greatest 211 | possible use to humanity, the best way to achieve this is to make it 212 | free software which everyone can redistribute and change under these 213 | terms. 214 | 215 | To do so, attach the following notices to the program. It is safest to 216 | attach them to the start of each source file to most effectively convey 217 | the exclusion of warranty; and each file should have at least the 218 | "copyright" line and a pointer to where the full notice is found. 219 | 220 | 221 | Copyright (C) 19yy 222 | 223 | This program is free software; you can redistribute it and/or modify 224 | it under the terms of the GNU General Public License as published by 225 | the Free Software Foundation; either version 1, or (at your option) 226 | any later version. 227 | 228 | This program is distributed in the hope that it will be useful, 229 | but WITHOUT ANY WARRANTY; without even the implied warranty of 230 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 231 | GNU General Public License for more details. 232 | 233 | You should have received a copy of the GNU General Public License 234 | along with this program; if not, write to the Free Software 235 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA 236 | 237 | 238 | Also add information on how to contact you by electronic and paper mail. 239 | 240 | If the program is interactive, make it output a short notice like this 241 | when it starts in an interactive mode: 242 | 243 | Gnomovision version 69, Copyright (C) 19xx name of author 244 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 245 | This is free software, and you are welcome to redistribute it 246 | under certain conditions; type `show c' for details. 247 | 248 | The hypothetical commands `show w' and `show c' should show the 249 | appropriate parts of the General Public License. Of course, the 250 | commands you use may be called something other than `show w' and `show 251 | c'; they could even be mouse-clicks or menu items--whatever suits your 252 | program. 253 | 254 | You should also get your employer (if you work as a programmer) or your 255 | school, if any, to sign a "copyright disclaimer" for the program, if 256 | necessary. Here a sample; alter the names: 257 | 258 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 259 | program `Gnomovision' (a program to direct compilers to make passes 260 | at assemblers) written by James Hacker. 261 | 262 | , 1 April 1989 263 | Ty Coon, President of Vice 264 | 265 | That's all there is to it! 266 | 267 | 268 | --- The Artistic License 1.0 --- 269 | 270 | This software is Copyright (c) 2022 by Gavin Hayes. 271 | 272 | This is free software, licensed under: 273 | 274 | The Artistic License 1.0 275 | 276 | The Artistic License 277 | 278 | Preamble 279 | 280 | The intent of this document is to state the conditions under which a Package 281 | may be copied, such that the Copyright Holder maintains some semblance of 282 | artistic control over the development of the package, while giving the users of 283 | the package the right to use and distribute the Package in a more-or-less 284 | customary fashion, plus the right to make reasonable modifications. 285 | 286 | Definitions: 287 | 288 | - "Package" refers to the collection of files distributed by the Copyright 289 | Holder, and derivatives of that collection of files created through 290 | textual modification. 291 | - "Standard Version" refers to such a Package if it has not been modified, 292 | or has been modified in accordance with the wishes of the Copyright 293 | Holder. 294 | - "Copyright Holder" is whoever is named in the copyright or copyrights for 295 | the package. 296 | - "You" is you, if you're thinking about copying or distributing this Package. 297 | - "Reasonable copying fee" is whatever you can justify on the basis of media 298 | cost, duplication charges, time of people involved, and so on. (You will 299 | not be required to justify it to the Copyright Holder, but only to the 300 | computing community at large as a market that must bear the fee.) 301 | - "Freely Available" means that no fee is charged for the item itself, though 302 | there may be fees involved in handling the item. It also means that 303 | recipients of the item may redistribute it under the same conditions they 304 | received it. 305 | 306 | 1. You may make and give away verbatim copies of the source form of the 307 | Standard Version of this Package without restriction, provided that you 308 | duplicate all of the original copyright notices and associated disclaimers. 309 | 310 | 2. You may apply bug fixes, portability fixes and other modifications derived 311 | from the Public Domain or from the Copyright Holder. A Package modified in such 312 | a way shall still be considered the Standard Version. 313 | 314 | 3. You may otherwise modify your copy of this Package in any way, provided that 315 | you insert a prominent notice in each changed file stating how and when you 316 | changed that file, and provided that you do at least ONE of the following: 317 | 318 | a) place your modifications in the Public Domain or otherwise make them 319 | Freely Available, such as by posting said modifications to Usenet or an 320 | equivalent medium, or placing the modifications on a major archive site 321 | such as ftp.uu.net, or by allowing the Copyright Holder to include your 322 | modifications in the Standard Version of the Package. 323 | 324 | b) use the modified Package only within your corporation or organization. 325 | 326 | c) rename any non-standard executables so the names do not conflict with 327 | standard executables, which must also be provided, and provide a separate 328 | manual page for each non-standard executable that clearly documents how it 329 | differs from the Standard Version. 330 | 331 | d) make other distribution arrangements with the Copyright Holder. 332 | 333 | 4. You may distribute the programs of this Package in object code or executable 334 | form, provided that you do at least ONE of the following: 335 | 336 | a) distribute a Standard Version of the executables and library files, 337 | together with instructions (in the manual page or equivalent) on where to 338 | get the Standard Version. 339 | 340 | b) accompany the distribution with the machine-readable source of the Package 341 | with your modifications. 342 | 343 | c) accompany any non-standard executables with their corresponding Standard 344 | Version executables, giving the non-standard executables non-standard 345 | names, and clearly documenting the differences in manual pages (or 346 | equivalent), together with instructions on where to get the Standard 347 | Version. 348 | 349 | d) make other distribution arrangements with the Copyright Holder. 350 | 351 | 5. You may charge a reasonable copying fee for any distribution of this 352 | Package. You may charge any fee you choose for support of this Package. You 353 | may not charge a fee for this Package itself. However, you may distribute this 354 | Package in aggregate with other (possibly commercial) programs as part of a 355 | larger (possibly commercial) software distribution provided that you do not 356 | advertise this Package as a product of your own. 357 | 358 | 6. The scripts and library files supplied as input to or produced as output 359 | from the programs of this Package do not automatically fall under the copyright 360 | of this Package, but belong to whomever generated them, and may be sold 361 | commercially, and may be aggregated with this Package. 362 | 363 | 7. C or perl subroutines supplied by you and linked into this Package shall not 364 | be considered part of this Package. 365 | 366 | 8. The name of the Copyright Holder may not be used to endorse or promote 367 | products derived from this software without specific prior written permission. 368 | 369 | 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED 370 | WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 371 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 372 | 373 | The End 374 | 375 | -------------------------------------------------------------------------------- /MANIFEST.SKIP: -------------------------------------------------------------------------------- 1 | # Avoid version control files. 2 | \bRCS\b 3 | \bCVS\b 4 | \bSCCS\b 5 | ,v$ 6 | \B\.svn\b 7 | \B\.git\b 8 | \B\.gitignore\b 9 | \b_darcs\b 10 | \B\.cvsignore$ 11 | 12 | # Avoid VMS specific MakeMaker generated files 13 | \bDescrip.MMS$ 14 | \bDESCRIP.MMS$ 15 | \bdescrip.mms$ 16 | 17 | # Avoid Makemaker generated and utility files. 18 | \bMANIFEST\.bak 19 | #\bMakefile$ 20 | ^Makefile$ 21 | \bblib/ 22 | \bMakeMaker-\d 23 | \bpm_to_blib\.ts$ 24 | \bpm_to_blib$ 25 | \bblibdirs\.ts$ # 6.18 through 6.25 generated this 26 | \b_eumm/ # 7.05_05 and above 27 | ^MANIFEST\.SKIP$ 28 | 29 | # Avoid Module::Build generated and utility files. 30 | \bBuild$ 31 | \b_build/ 32 | \bBuild.bat$ 33 | \bBuild.COM$ 34 | \bBUILD.COM$ 35 | \bbuild.com$ 36 | 37 | # and Module::Build::Tiny generated files 38 | \b_build_params$ 39 | 40 | # Avoid temp and backup files. 41 | ~$ 42 | \.old$ 43 | \#$ 44 | \b\.# 45 | \.bak$ 46 | \.tmp$ 47 | \.# 48 | \.rej$ 49 | \..*\.sw.?$ 50 | 51 | # Avoid OS-specific files/dirs 52 | # Mac OSX metadata 53 | \B\.DS_Store 54 | # Mac OSX SMB mount metadata files 55 | \B\._ 56 | 57 | # Avoid Devel::Cover and Devel::CoverX::Covered files. 58 | \bcover_db\b 59 | \bcovered\b 60 | 61 | # Avoid prove files 62 | \B\.prove$ 63 | 64 | # Avoid MYMETA files 65 | ^MYMETA\. 66 | 67 | # Avoid github actions 68 | \B\.github\b 69 | 70 | # Avoid various APPerl files 71 | apperl-project.json 72 | \.tar\.gz$ 73 | \.com(\.dbg)?$ 74 | ^tests_temp 75 | ^.apperl 76 | ^Perl-Dist-APPerl-v 77 | 78 | #Avoid cpanfile 79 | cpanfile 80 | -------------------------------------------------------------------------------- /Makefile.PL: -------------------------------------------------------------------------------- 1 | use 5.010; 2 | use strict; 3 | use warnings; 4 | use ExtUtils::MakeMaker; 5 | use File::ShareDir::Install; 6 | 7 | install_share 'share'; 8 | 9 | my %WriteMakefileArgs = ( 10 | NAME => 'Perl::Dist::APPerl', 11 | AUTHOR => "Gavin Hayes ", 12 | VERSION_FROM => 'lib/Perl/Dist/APPerl.pm', 13 | ABSTRACT_FROM => 'lib/Perl/Dist/APPerl.pm', 14 | LICENSE => 'perl_5', 15 | MIN_PERL_VERSION => '5.010', 16 | CONFIGURE_REQUIRES => { 17 | 'ExtUtils::MakeMaker' => '0', 18 | "File::ShareDir::Install" => "0.13" 19 | }, 20 | PREREQ_PM => { 21 | 'JSON::PP' => '2.0104', 22 | 'File::Path' => '2.07', 23 | 'version' => '0.77', 24 | "File::ShareDir" => 0, 25 | }, 26 | TEST_REQUIRES => { 27 | 'Test::Pod::LinkCheck::Lite' => '0', 28 | }, 29 | EXE_FILES => ['script/apperlm'], 30 | dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', }, 31 | clean => { FILES => ['Perl-Dist-APPerl-*', '*.com*', 'tests_temp']}, 32 | META_MERGE => { 33 | 'meta-spec' => { version => 2 }, 34 | resources => { 35 | repository => { 36 | type => 'git', 37 | url => 'https://github.com/G4Vi/Perl-Dist-APPerl.git', 38 | web => 'https://github.com/G4Vi/Perl-Dist-APPerl', 39 | }, 40 | bugtracker => { 41 | web => 'https://github.com/G4Vi/Perl-Dist-APPerl/issues' 42 | }, 43 | homepage => 'https://computoid.com/APPerl', 44 | }, 45 | 'dynamic_config' => 0, 46 | 'x_static_install' => 1 47 | }, 48 | ); 49 | 50 | # Compatibility with old versions of ExtUtils::MakeMaker 51 | unless (eval { ExtUtils::MakeMaker->VERSION('6.64'); 1 }) { 52 | my $test_requires = delete $WriteMakefileArgs{TEST_REQUIRES} || {}; 53 | @{$WriteMakefileArgs{PREREQ_PM}}{keys %$test_requires} = values %$test_requires; 54 | } 55 | 56 | unless (eval { ExtUtils::MakeMaker->VERSION('6.55_03'); 1 }) { 57 | my $build_requires = delete $WriteMakefileArgs{BUILD_REQUIRES} || {}; 58 | @{$WriteMakefileArgs{PREREQ_PM}}{keys %$build_requires} = values %$build_requires; 59 | } 60 | 61 | my %min_eumm_version = ( 62 | CONFIGURE_REQUIRES => '6.52', 63 | MIN_PERL_VERSION => '6.48', 64 | LICENSE => '6.31', 65 | META_MERGE => '6.46', 66 | ); 67 | for my $parameter ( keys %min_eumm_version ) { 68 | delete $WriteMakefileArgs{$parameter} 69 | unless eval { 70 | ExtUtils::MakeMaker->VERSION( $min_eumm_version{$parameter} ); 71 | 1; 72 | }; 73 | } 74 | 75 | WriteMakefile(%WriteMakefileArgs); 76 | 77 | sub MY::postamble { 78 | return File::ShareDir::Install::postamble(@_) . "\n" 79 | ."authortest: test\n\tAUTHOR_TESTING=1 " 80 | . $_[0]->test_via_harness( '$(FULLPERLRUN)', 'xt/author/*.t' ); 81 | } 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Perl-Dist-APPerl 2 | [Actually Portable Perl](https://computoid.com/APPerl/) 3 | 4 | ## DESCRIPTION 5 | 6 | Actually Portable Perl (APPerl) is a distribution of Perl the runs on 7 | several x86_64 operating systems via the same binary. It builds to a 8 | single binary with perl modules packed inside of it. 9 | 10 | Cross-platform, single binary, standalone Perl applications can be made 11 | by building custom versions of APPerl, with and without compiling 12 | Perl from scratch, so it can be used an alternative to **PAR::Packer**. 13 | APPerl could also easily be added to development SDKs, 14 | carried on your USB drive, or just allow you to run the exact same perl 15 | on all your PCs multiple computers. 16 | 17 | Information on the creation of APPerl can be found in this 18 | [blogpost](https://computoid.com/posts/Perl-is-Actually-Portable.html). 19 | 20 | ## NON-PERL DEPENDENCIES 21 | 22 | A `zip` binary ([Info-ZIP](https://infozip.sourceforge.net/)) is 23 | required to build. Your distro likely has it in its package 24 | repository. For Windows, the official download is available via FTP 25 | . 26 | 27 | ### Windows x64 Info-ZIP download and install instructions 28 | - Get an FTP client if needed: [WinSCP](https://winscp.net/eng/index.php) 29 | - Connect to the [InfoZip FTP server](ftp://ftp.info-zip.org/pub/infozip/) with anonymous login. 30 | - Enter the `win32` folder and download `zip300xn-x64.zip`. 31 | - Extract the zip file and its inner zip file. 32 | - Add the folder containing `zip.exe` to `%PATH%`: [step-by-step](https://www.computerhope.com/issues/ch000549.htm) 33 | 34 | The last step isn't strictly necessary, the absolute path to a zip binary may be passed in to `apperlm build` with the `--zippath` arg. 35 | 36 | ## TRADITIONAL INSTALLATION 37 | 38 | To install this module, run the following commands: 39 | ``` 40 | perl Makefile.PL 41 | make 42 | make test 43 | make install 44 | ``` 45 | 46 | ## BOOTSTRAPPING 47 | 48 | To handle the chicken-and egg-situation of needing Perl to build 49 | APPerl, APPerl may be bootstrapped from an existing build of APPerl. 50 | See [releases](https://github.com/G4Vi/Perl-Dist-APPerl/releases) and 51 | pick a "full" build. From inside a copy of this repo, you can run 52 | `apperlm` as follows: `./perl.com -Ilib script/apperlm` 53 | 54 | `apperlm` is actually included in a full build of APPerl too. 55 | ``` 56 | ln -s perl.com apperlm 57 | ./apperlm 58 | ``` 59 | 60 | ## SUPPORT AND DOCUMENTATION 61 | 62 | You can find documentation for this module with the perldoc command. 63 | 64 | `perldoc Perl::Dist::APPerl` 65 | 66 | More information may be available at the [APPerl webpage](https://computoid.com/APPerl/) 67 | 68 | Support and bug reports can be found at the repository 69 | 70 | ## LICENSE AND COPYRIGHT 71 | 72 | This software is copyright (c) 2022 by Gavin Hayes. 73 | 74 | This is free software; you can redistribute it and/or modify it under 75 | the same terms as the Perl 5 programming language system itself. See LICENSE. 76 | -------------------------------------------------------------------------------- /cpanfile: -------------------------------------------------------------------------------- 1 | requires 'File::ShareDir::Install', '0.13'; 2 | requires 'File::ShareDir', '0'; 3 | -------------------------------------------------------------------------------- /lib/Perl/Dist/APPerl.pm: -------------------------------------------------------------------------------- 1 | package Perl::Dist::APPerl; 2 | # Copyright (c) 2024 Gavin Hayes, see LICENSE in the root of the project 3 | use version 0.77; our $VERSION = qv(v0.6.1); 4 | use strict; 5 | use warnings; 6 | use JSON::PP 2.0104 qw(decode_json); 7 | use File::Path 2.07 qw(make_path remove_tree); 8 | use Cwd qw(abs_path getcwd); 9 | use Data::Dumper qw(Dumper); 10 | use File::Basename qw(basename dirname); 11 | use File::Copy qw(copy move cp); 12 | use FindBin qw(); 13 | use Fcntl qw(SEEK_SET); 14 | use Getopt::Long qw(GetOptionsFromArray); 15 | Getopt::Long::Configure qw(gnu_getopt); 16 | 17 | use constant { 18 | START_WD => getcwd(), 19 | PROJECT_FILE => 'apperl-project.json', 20 | }; 21 | use constant { 22 | PROJECT_TMP_DIR => (START_WD.'/.apperl'), 23 | }; 24 | use constant { 25 | # DEFDATAROOT is used if the XDG base directories cannot be found 26 | DEFDATAROOT => defined($ENV{HOME}) ? $ENV{HOME} 27 | : defined($ENV{APPDATA}) ? $ENV{APPDATA} .'/apperl' 28 | : PROJECT_TMP_DIR.'/site', 29 | PROJECT_TMP_CONFIG_FILE => (PROJECT_TMP_DIR.'/user-project.json'), 30 | }; 31 | use constant { 32 | SITE_CONFIG_DIR => ($ENV{XDG_CONFIG_HOME} // (DEFDATAROOT.'/.config')) . '/apperl', 33 | SITE_REPO_DIR => ($ENV{XDG_DATA_HOME} // (DEFDATAROOT.'/.local/share')).'/apperl', 34 | }; 35 | use constant { 36 | SITE_CONFIG_FILE => (SITE_CONFIG_DIR."/site.json"), 37 | }; 38 | use constant { 39 | SHARE_DIR => sub { 40 | my $thispath = abs_path(__FILE__); 41 | defined($thispath) or die(__FILE__.'issues?'); 42 | my $sharedir = dirname($thispath)."/../../../share"; 43 | if (! -d $sharedir) { 44 | $sharedir = '/zip/lib/perl5/auto/share/dist/Perl-Dist-APPerl'; 45 | } 46 | if (! -d $sharedir) { 47 | eval "use File::ShareDir; 1" or die "Failed to load File::ShareDir"; 48 | $sharedir = File::ShareDir::dist_dir('Perl-Dist-APPerl'); 49 | } 50 | $sharedir = abs_path($sharedir) // die "Failed to load sharedir"; 51 | return $sharedir; 52 | }->() 53 | }; 54 | 55 | sub _load_apperl_configs { 56 | 57 | # https://packages.debian.org/experimental/amd64/perl-base/filelist with tweaks 58 | my @smallmanifest = ( 59 | '__perllib__/AutoLoader.pm', 60 | '__perllib__/Carp.pm', 61 | '__perllib__/Carp/Heavy.pm', 62 | '__perlarchlib__/Config.pm', 63 | '__perlarchlib__/Config_git.pl', 64 | '__perlarchlib__/Config_heavy.pl', 65 | '__perlarchlib__/Cwd.pm', 66 | '__perlarchlib__/DynaLoader.pm', 67 | '__perlarchlib__/Errno.pm', 68 | '__perlarchlib__/ErrnoRuntime.pm', 69 | '__perllib__/Exporter.pm', 70 | '__perllib__/Exporter/Heavy.pm', 71 | '__perlarchlib__/Fcntl.pm', 72 | '__perllib__/File/Basename.pm', 73 | '__perlarchlib__/File/Glob.pm', 74 | '__perllib__/File/Path.pm', 75 | '__perlarchlib__/File/Spec.pm', 76 | '__perlarchlib__/File/Spec/Unix.pm', 77 | '__perllib__/File/Temp.pm', 78 | '__perllib__/FileHandle.pm', 79 | '__perllib__/Getopt/Long.pm', 80 | '__perlarchlib__/Hash/Util.pm', 81 | '__perlarchlib__/IO.pm', 82 | '__perlarchlib__/IO/File.pm', 83 | '__perlarchlib__/IO/Handle.pm', 84 | '__perlarchlib__/IO/Pipe.pm', 85 | '__perlarchlib__/IO/Seekable.pm', 86 | '__perlarchlib__/IO/Select.pm', 87 | '__perlarchlib__/IO/Socket.pm', 88 | '__perlarchlib__/IO/Socket/INET.pm', 89 | '__perllib__/IO/Socket/IP.pm', 90 | '__perlarchlib__/IO/Socket/UNIX.pm', 91 | '__perllib__/IPC/Open2.pm', 92 | '__perllib__/IPC/Open3.pm', 93 | '__perlarchlib__/List/Util.pm', 94 | '__perlarchlib__/POSIX.pm', 95 | '__perlarchlib__/Scalar/Util.pm', 96 | '__perllib__/SelectSaver.pm', 97 | '__perlarchlib__/Socket.pm', 98 | '__perllib__/Symbol.pm', 99 | '__perllib__/Text/ParseWords.pm', 100 | '__perllib__/Text/Tabs.pm', 101 | '__perllib__/Text/Wrap.pm', 102 | '__perllib__/Tie/Hash.pm', 103 | '__perllib__/XSLoader.pm', 104 | '__perlarchlib__/attributes.pm', 105 | '__perllib__/base.pm', 106 | '__perllib__/builtin.pm', 107 | '__perllib__/bytes.pm', 108 | '__perllib__/bytes_heavy.pl', 109 | '__perllib__/constant.pm', 110 | '__perllib__/feature.pm', 111 | '__perllib__/fields.pm', 112 | '__perllib__/integer.pm', 113 | '__perlarchlib__/lib.pm', 114 | '__perllib__/locale.pm', 115 | '__perllib__/overload.pm', 116 | '__perllib__/overloading.pm', 117 | '__perllib__/parent.pm', 118 | '__perlarchlib__/re.pm', 119 | '__perllib__/strict.pm', 120 | '__perllib__/unicore/To/Age.pl', 121 | '__perllib__/unicore/To/Bc.pl', 122 | '__perllib__/unicore/To/Bmg.pl', 123 | '__perllib__/unicore/To/Bpb.pl', 124 | '__perllib__/unicore/To/Bpt.pl', 125 | '__perllib__/unicore/To/Cf.pl', 126 | '__perllib__/unicore/To/Ea.pl', 127 | '__perllib__/unicore/To/EqUIdeo.pl', 128 | '__perllib__/unicore/To/GCB.pl', 129 | '__perllib__/unicore/To/Gc.pl', 130 | '__perllib__/unicore/To/Hst.pl', 131 | '__perllib__/unicore/To/Identif2.pl', 132 | '__perllib__/unicore/To/Identifi.pl', 133 | '__perllib__/unicore/To/InPC.pl', 134 | '__perllib__/unicore/To/InSC.pl', 135 | '__perllib__/unicore/To/Isc.pl', 136 | '__perllib__/unicore/To/Jg.pl', 137 | '__perllib__/unicore/To/Jt.pl', 138 | '__perllib__/unicore/To/Lb.pl', 139 | '__perllib__/unicore/To/Lc.pl', 140 | '__perllib__/unicore/To/NFCQC.pl', 141 | '__perllib__/unicore/To/NFDQC.pl', 142 | '__perllib__/unicore/To/NFKCCF.pl', 143 | '__perllib__/unicore/To/NFKCQC.pl', 144 | '__perllib__/unicore/To/NFKDQC.pl', 145 | '__perllib__/unicore/To/Na1.pl', 146 | '__perllib__/unicore/To/NameAlia.pl', 147 | '__perllib__/unicore/To/Nt.pl', 148 | '__perllib__/unicore/To/Nv.pl', 149 | '__perllib__/unicore/To/PerlDeci.pl', 150 | '__perllib__/unicore/To/SB.pl', 151 | '__perllib__/unicore/To/Sc.pl', 152 | '__perllib__/unicore/To/Scx.pl', 153 | '__perllib__/unicore/To/Tc.pl', 154 | '__perllib__/unicore/To/Uc.pl', 155 | '__perllib__/unicore/To/Vo.pl', 156 | '__perllib__/unicore/To/WB.pl', 157 | '__perllib__/unicore/To/_PerlLB.pl', 158 | '__perllib__/unicore/To/_PerlSCX.pl', 159 | '__perllib__/unicore/lib/Age/NA.pl', 160 | '__perllib__/unicore/lib/Age/V100.pl', 161 | '__perllib__/unicore/lib/Age/V11.pl', 162 | '__perllib__/unicore/lib/Age/V110.pl', 163 | '__perllib__/unicore/lib/Age/V120.pl', 164 | '__perllib__/unicore/lib/Age/V130.pl', 165 | '__perllib__/unicore/lib/Age/V140.pl', 166 | '__perllib__/unicore/lib/Age/V20.pl', 167 | '__perllib__/unicore/lib/Age/V30.pl', 168 | '__perllib__/unicore/lib/Age/V31.pl', 169 | '__perllib__/unicore/lib/Age/V32.pl', 170 | '__perllib__/unicore/lib/Age/V40.pl', 171 | '__perllib__/unicore/lib/Age/V41.pl', 172 | '__perllib__/unicore/lib/Age/V50.pl', 173 | '__perllib__/unicore/lib/Age/V51.pl', 174 | '__perllib__/unicore/lib/Age/V52.pl', 175 | '__perllib__/unicore/lib/Age/V60.pl', 176 | '__perllib__/unicore/lib/Age/V61.pl', 177 | '__perllib__/unicore/lib/Age/V70.pl', 178 | '__perllib__/unicore/lib/Age/V80.pl', 179 | '__perllib__/unicore/lib/Age/V90.pl', 180 | '__perllib__/unicore/lib/Alpha/Y.pl', 181 | '__perllib__/unicore/lib/Bc/AL.pl', 182 | '__perllib__/unicore/lib/Bc/AN.pl', 183 | '__perllib__/unicore/lib/Bc/B.pl', 184 | '__perllib__/unicore/lib/Bc/BN.pl', 185 | '__perllib__/unicore/lib/Bc/CS.pl', 186 | '__perllib__/unicore/lib/Bc/EN.pl', 187 | '__perllib__/unicore/lib/Bc/ES.pl', 188 | '__perllib__/unicore/lib/Bc/ET.pl', 189 | '__perllib__/unicore/lib/Bc/L.pl', 190 | '__perllib__/unicore/lib/Bc/NSM.pl', 191 | '__perllib__/unicore/lib/Bc/ON.pl', 192 | '__perllib__/unicore/lib/Bc/R.pl', 193 | '__perllib__/unicore/lib/Bc/WS.pl', 194 | '__perllib__/unicore/lib/BidiC/Y.pl', 195 | '__perllib__/unicore/lib/BidiM/Y.pl', 196 | '__perllib__/unicore/lib/Blk/NB.pl', 197 | '__perllib__/unicore/lib/Bpt/C.pl', 198 | '__perllib__/unicore/lib/Bpt/N.pl', 199 | '__perllib__/unicore/lib/Bpt/O.pl', 200 | '__perllib__/unicore/lib/CE/Y.pl', 201 | '__perllib__/unicore/lib/CI/Y.pl', 202 | '__perllib__/unicore/lib/CWCF/Y.pl', 203 | '__perllib__/unicore/lib/CWCM/Y.pl', 204 | '__perllib__/unicore/lib/CWKCF/Y.pl', 205 | '__perllib__/unicore/lib/CWL/Y.pl', 206 | '__perllib__/unicore/lib/CWT/Y.pl', 207 | '__perllib__/unicore/lib/CWU/Y.pl', 208 | '__perllib__/unicore/lib/Cased/Y.pl', 209 | '__perllib__/unicore/lib/Ccc/A.pl', 210 | '__perllib__/unicore/lib/Ccc/AL.pl', 211 | '__perllib__/unicore/lib/Ccc/AR.pl', 212 | '__perllib__/unicore/lib/Ccc/ATAR.pl', 213 | '__perllib__/unicore/lib/Ccc/B.pl', 214 | '__perllib__/unicore/lib/Ccc/BR.pl', 215 | '__perllib__/unicore/lib/Ccc/DB.pl', 216 | '__perllib__/unicore/lib/Ccc/NK.pl', 217 | '__perllib__/unicore/lib/Ccc/NR.pl', 218 | '__perllib__/unicore/lib/Ccc/OV.pl', 219 | '__perllib__/unicore/lib/Ccc/VR.pl', 220 | '__perllib__/unicore/lib/CompEx/Y.pl', 221 | '__perllib__/unicore/lib/DI/Y.pl', 222 | '__perllib__/unicore/lib/Dash/Y.pl', 223 | '__perllib__/unicore/lib/Dep/Y.pl', 224 | '__perllib__/unicore/lib/Dia/Y.pl', 225 | '__perllib__/unicore/lib/Dt/Com.pl', 226 | '__perllib__/unicore/lib/Dt/Enc.pl', 227 | '__perllib__/unicore/lib/Dt/Fin.pl', 228 | '__perllib__/unicore/lib/Dt/Font.pl', 229 | '__perllib__/unicore/lib/Dt/Init.pl', 230 | '__perllib__/unicore/lib/Dt/Iso.pl', 231 | '__perllib__/unicore/lib/Dt/Med.pl', 232 | '__perllib__/unicore/lib/Dt/Nar.pl', 233 | '__perllib__/unicore/lib/Dt/Nb.pl', 234 | '__perllib__/unicore/lib/Dt/NonCanon.pl', 235 | '__perllib__/unicore/lib/Dt/Sqr.pl', 236 | '__perllib__/unicore/lib/Dt/Sub.pl', 237 | '__perllib__/unicore/lib/Dt/Sup.pl', 238 | '__perllib__/unicore/lib/Dt/Vert.pl', 239 | '__perllib__/unicore/lib/EBase/Y.pl', 240 | '__perllib__/unicore/lib/EComp/Y.pl', 241 | '__perllib__/unicore/lib/EPres/Y.pl', 242 | '__perllib__/unicore/lib/Ea/A.pl', 243 | '__perllib__/unicore/lib/Ea/H.pl', 244 | '__perllib__/unicore/lib/Ea/N.pl', 245 | '__perllib__/unicore/lib/Ea/Na.pl', 246 | '__perllib__/unicore/lib/Ea/W.pl', 247 | '__perllib__/unicore/lib/Emoji/Y.pl', 248 | '__perllib__/unicore/lib/Ext/Y.pl', 249 | '__perllib__/unicore/lib/ExtPict/Y.pl', 250 | '__perllib__/unicore/lib/GCB/CN.pl', 251 | '__perllib__/unicore/lib/GCB/EX.pl', 252 | '__perllib__/unicore/lib/GCB/LV.pl', 253 | '__perllib__/unicore/lib/GCB/LVT.pl', 254 | '__perllib__/unicore/lib/GCB/PP.pl', 255 | '__perllib__/unicore/lib/GCB/SM.pl', 256 | '__perllib__/unicore/lib/GCB/XX.pl', 257 | '__perllib__/unicore/lib/Gc/C.pl', 258 | '__perllib__/unicore/lib/Gc/Cf.pl', 259 | '__perllib__/unicore/lib/Gc/Cn.pl', 260 | '__perllib__/unicore/lib/Gc/L.pl', 261 | '__perllib__/unicore/lib/Gc/LC.pl', 262 | '__perllib__/unicore/lib/Gc/Ll.pl', 263 | '__perllib__/unicore/lib/Gc/Lm.pl', 264 | '__perllib__/unicore/lib/Gc/Lo.pl', 265 | '__perllib__/unicore/lib/Gc/Lu.pl', 266 | '__perllib__/unicore/lib/Gc/M.pl', 267 | '__perllib__/unicore/lib/Gc/Mc.pl', 268 | '__perllib__/unicore/lib/Gc/Me.pl', 269 | '__perllib__/unicore/lib/Gc/Mn.pl', 270 | '__perllib__/unicore/lib/Gc/N.pl', 271 | '__perllib__/unicore/lib/Gc/Nd.pl', 272 | '__perllib__/unicore/lib/Gc/Nl.pl', 273 | '__perllib__/unicore/lib/Gc/No.pl', 274 | '__perllib__/unicore/lib/Gc/P.pl', 275 | '__perllib__/unicore/lib/Gc/Pc.pl', 276 | '__perllib__/unicore/lib/Gc/Pd.pl', 277 | '__perllib__/unicore/lib/Gc/Pe.pl', 278 | '__perllib__/unicore/lib/Gc/Pf.pl', 279 | '__perllib__/unicore/lib/Gc/Pi.pl', 280 | '__perllib__/unicore/lib/Gc/Po.pl', 281 | '__perllib__/unicore/lib/Gc/Ps.pl', 282 | '__perllib__/unicore/lib/Gc/S.pl', 283 | '__perllib__/unicore/lib/Gc/Sc.pl', 284 | '__perllib__/unicore/lib/Gc/Sk.pl', 285 | '__perllib__/unicore/lib/Gc/Sm.pl', 286 | '__perllib__/unicore/lib/Gc/So.pl', 287 | '__perllib__/unicore/lib/Gc/Z.pl', 288 | '__perllib__/unicore/lib/Gc/Zs.pl', 289 | '__perllib__/unicore/lib/GrBase/Y.pl', 290 | '__perllib__/unicore/lib/GrExt/Y.pl', 291 | '__perllib__/unicore/lib/Hex/Y.pl', 292 | '__perllib__/unicore/lib/Hst/NA.pl', 293 | '__perllib__/unicore/lib/Hyphen/T.pl', 294 | '__perllib__/unicore/lib/IDC/Y.pl', 295 | '__perllib__/unicore/lib/IDS/Y.pl', 296 | '__perllib__/unicore/lib/IdStatus/Allowed.pl', 297 | '__perllib__/unicore/lib/IdStatus/Restrict.pl', 298 | '__perllib__/unicore/lib/IdType/DefaultI.pl', 299 | '__perllib__/unicore/lib/IdType/Exclusio.pl', 300 | '__perllib__/unicore/lib/IdType/Inclusio.pl', 301 | '__perllib__/unicore/lib/IdType/LimitedU.pl', 302 | '__perllib__/unicore/lib/IdType/NotChara.pl', 303 | '__perllib__/unicore/lib/IdType/NotNFKC.pl', 304 | '__perllib__/unicore/lib/IdType/NotXID.pl', 305 | '__perllib__/unicore/lib/IdType/Obsolete.pl', 306 | '__perllib__/unicore/lib/IdType/Recommen.pl', 307 | '__perllib__/unicore/lib/IdType/Technica.pl', 308 | '__perllib__/unicore/lib/IdType/Uncommon.pl', 309 | '__perllib__/unicore/lib/Ideo/Y.pl', 310 | '__perllib__/unicore/lib/In/10_0.pl', 311 | '__perllib__/unicore/lib/In/11_0.pl', 312 | '__perllib__/unicore/lib/In/12_0.pl', 313 | '__perllib__/unicore/lib/In/12_1.pl', 314 | '__perllib__/unicore/lib/In/13_0.pl', 315 | '__perllib__/unicore/lib/In/14_0.pl', 316 | '__perllib__/unicore/lib/In/2_0.pl', 317 | '__perllib__/unicore/lib/In/2_1.pl', 318 | '__perllib__/unicore/lib/In/3_0.pl', 319 | '__perllib__/unicore/lib/In/3_1.pl', 320 | '__perllib__/unicore/lib/In/3_2.pl', 321 | '__perllib__/unicore/lib/In/4_0.pl', 322 | '__perllib__/unicore/lib/In/4_1.pl', 323 | '__perllib__/unicore/lib/In/5_0.pl', 324 | '__perllib__/unicore/lib/In/5_1.pl', 325 | '__perllib__/unicore/lib/In/5_2.pl', 326 | '__perllib__/unicore/lib/In/6_0.pl', 327 | '__perllib__/unicore/lib/In/6_1.pl', 328 | '__perllib__/unicore/lib/In/6_2.pl', 329 | '__perllib__/unicore/lib/In/6_3.pl', 330 | '__perllib__/unicore/lib/In/7_0.pl', 331 | '__perllib__/unicore/lib/In/8_0.pl', 332 | '__perllib__/unicore/lib/In/9_0.pl', 333 | '__perllib__/unicore/lib/InPC/Bottom.pl', 334 | '__perllib__/unicore/lib/InPC/BottomAn.pl', 335 | '__perllib__/unicore/lib/InPC/Left.pl', 336 | '__perllib__/unicore/lib/InPC/LeftAndR.pl', 337 | '__perllib__/unicore/lib/InPC/NA.pl', 338 | '__perllib__/unicore/lib/InPC/Overstru.pl', 339 | '__perllib__/unicore/lib/InPC/Right.pl', 340 | '__perllib__/unicore/lib/InPC/Top.pl', 341 | '__perllib__/unicore/lib/InPC/TopAndBo.pl', 342 | '__perllib__/unicore/lib/InPC/TopAndL2.pl', 343 | '__perllib__/unicore/lib/InPC/TopAndLe.pl', 344 | '__perllib__/unicore/lib/InPC/TopAndRi.pl', 345 | '__perllib__/unicore/lib/InPC/VisualOr.pl', 346 | '__perllib__/unicore/lib/InSC/Avagraha.pl', 347 | '__perllib__/unicore/lib/InSC/Bindu.pl', 348 | '__perllib__/unicore/lib/InSC/Cantilla.pl', 349 | '__perllib__/unicore/lib/InSC/Consona2.pl', 350 | '__perllib__/unicore/lib/InSC/Consona3.pl', 351 | '__perllib__/unicore/lib/InSC/Consona4.pl', 352 | '__perllib__/unicore/lib/InSC/Consona5.pl', 353 | '__perllib__/unicore/lib/InSC/Consona6.pl', 354 | '__perllib__/unicore/lib/InSC/Consona7.pl', 355 | '__perllib__/unicore/lib/InSC/Consona8.pl', 356 | '__perllib__/unicore/lib/InSC/Consonan.pl', 357 | '__perllib__/unicore/lib/InSC/Invisibl.pl', 358 | '__perllib__/unicore/lib/InSC/Nukta.pl', 359 | '__perllib__/unicore/lib/InSC/Number.pl', 360 | '__perllib__/unicore/lib/InSC/Other.pl', 361 | '__perllib__/unicore/lib/InSC/PureKill.pl', 362 | '__perllib__/unicore/lib/InSC/Syllable.pl', 363 | '__perllib__/unicore/lib/InSC/ToneMark.pl', 364 | '__perllib__/unicore/lib/InSC/Virama.pl', 365 | '__perllib__/unicore/lib/InSC/Visarga.pl', 366 | '__perllib__/unicore/lib/InSC/Vowel.pl', 367 | '__perllib__/unicore/lib/InSC/VowelDep.pl', 368 | '__perllib__/unicore/lib/InSC/VowelInd.pl', 369 | '__perllib__/unicore/lib/Jg/Ain.pl', 370 | '__perllib__/unicore/lib/Jg/Alef.pl', 371 | '__perllib__/unicore/lib/Jg/Beh.pl', 372 | '__perllib__/unicore/lib/Jg/Dal.pl', 373 | '__perllib__/unicore/lib/Jg/FarsiYeh.pl', 374 | '__perllib__/unicore/lib/Jg/Feh.pl', 375 | '__perllib__/unicore/lib/Jg/Gaf.pl', 376 | '__perllib__/unicore/lib/Jg/Hah.pl', 377 | '__perllib__/unicore/lib/Jg/HanifiRo.pl', 378 | '__perllib__/unicore/lib/Jg/Kaf.pl', 379 | '__perllib__/unicore/lib/Jg/Lam.pl', 380 | '__perllib__/unicore/lib/Jg/NoJoinin.pl', 381 | '__perllib__/unicore/lib/Jg/Noon.pl', 382 | '__perllib__/unicore/lib/Jg/Qaf.pl', 383 | '__perllib__/unicore/lib/Jg/Reh.pl', 384 | '__perllib__/unicore/lib/Jg/Sad.pl', 385 | '__perllib__/unicore/lib/Jg/Seen.pl', 386 | '__perllib__/unicore/lib/Jg/Tah.pl', 387 | '__perllib__/unicore/lib/Jg/Waw.pl', 388 | '__perllib__/unicore/lib/Jg/Yeh.pl', 389 | '__perllib__/unicore/lib/Jt/C.pl', 390 | '__perllib__/unicore/lib/Jt/D.pl', 391 | '__perllib__/unicore/lib/Jt/L.pl', 392 | '__perllib__/unicore/lib/Jt/R.pl', 393 | '__perllib__/unicore/lib/Jt/T.pl', 394 | '__perllib__/unicore/lib/Jt/U.pl', 395 | '__perllib__/unicore/lib/Lb/AI.pl', 396 | '__perllib__/unicore/lib/Lb/AL.pl', 397 | '__perllib__/unicore/lib/Lb/BA.pl', 398 | '__perllib__/unicore/lib/Lb/BB.pl', 399 | '__perllib__/unicore/lib/Lb/CJ.pl', 400 | '__perllib__/unicore/lib/Lb/CL.pl', 401 | '__perllib__/unicore/lib/Lb/CM.pl', 402 | '__perllib__/unicore/lib/Lb/EX.pl', 403 | '__perllib__/unicore/lib/Lb/GL.pl', 404 | '__perllib__/unicore/lib/Lb/ID.pl', 405 | '__perllib__/unicore/lib/Lb/IN.pl', 406 | '__perllib__/unicore/lib/Lb/IS.pl', 407 | '__perllib__/unicore/lib/Lb/NS.pl', 408 | '__perllib__/unicore/lib/Lb/NU.pl', 409 | '__perllib__/unicore/lib/Lb/OP.pl', 410 | '__perllib__/unicore/lib/Lb/PO.pl', 411 | '__perllib__/unicore/lib/Lb/PR.pl', 412 | '__perllib__/unicore/lib/Lb/QU.pl', 413 | '__perllib__/unicore/lib/Lb/SA.pl', 414 | '__perllib__/unicore/lib/Lb/XX.pl', 415 | '__perllib__/unicore/lib/Lower/Y.pl', 416 | '__perllib__/unicore/lib/Math/Y.pl', 417 | '__perllib__/unicore/lib/NFCQC/M.pl', 418 | '__perllib__/unicore/lib/NFCQC/Y.pl', 419 | '__perllib__/unicore/lib/NFDQC/N.pl', 420 | '__perllib__/unicore/lib/NFDQC/Y.pl', 421 | '__perllib__/unicore/lib/NFKCQC/N.pl', 422 | '__perllib__/unicore/lib/NFKCQC/Y.pl', 423 | '__perllib__/unicore/lib/NFKDQC/N.pl', 424 | '__perllib__/unicore/lib/NFKDQC/Y.pl', 425 | '__perllib__/unicore/lib/Nt/Di.pl', 426 | '__perllib__/unicore/lib/Nt/None.pl', 427 | '__perllib__/unicore/lib/Nt/Nu.pl', 428 | '__perllib__/unicore/lib/Nv/0.pl', 429 | '__perllib__/unicore/lib/Nv/1.pl', 430 | '__perllib__/unicore/lib/Nv/10.pl', 431 | '__perllib__/unicore/lib/Nv/100.pl', 432 | '__perllib__/unicore/lib/Nv/1000.pl', 433 | '__perllib__/unicore/lib/Nv/10000.pl', 434 | '__perllib__/unicore/lib/Nv/100000.pl', 435 | '__perllib__/unicore/lib/Nv/11.pl', 436 | '__perllib__/unicore/lib/Nv/12.pl', 437 | '__perllib__/unicore/lib/Nv/13.pl', 438 | '__perllib__/unicore/lib/Nv/14.pl', 439 | '__perllib__/unicore/lib/Nv/15.pl', 440 | '__perllib__/unicore/lib/Nv/16.pl', 441 | '__perllib__/unicore/lib/Nv/17.pl', 442 | '__perllib__/unicore/lib/Nv/18.pl', 443 | '__perllib__/unicore/lib/Nv/19.pl', 444 | '__perllib__/unicore/lib/Nv/1_16.pl', 445 | '__perllib__/unicore/lib/Nv/1_2.pl', 446 | '__perllib__/unicore/lib/Nv/1_3.pl', 447 | '__perllib__/unicore/lib/Nv/1_4.pl', 448 | '__perllib__/unicore/lib/Nv/1_6.pl', 449 | '__perllib__/unicore/lib/Nv/1_8.pl', 450 | '__perllib__/unicore/lib/Nv/2.pl', 451 | '__perllib__/unicore/lib/Nv/20.pl', 452 | '__perllib__/unicore/lib/Nv/200.pl', 453 | '__perllib__/unicore/lib/Nv/2000.pl', 454 | '__perllib__/unicore/lib/Nv/20000.pl', 455 | '__perllib__/unicore/lib/Nv/2_3.pl', 456 | '__perllib__/unicore/lib/Nv/3.pl', 457 | '__perllib__/unicore/lib/Nv/30.pl', 458 | '__perllib__/unicore/lib/Nv/300.pl', 459 | '__perllib__/unicore/lib/Nv/3000.pl', 460 | '__perllib__/unicore/lib/Nv/30000.pl', 461 | '__perllib__/unicore/lib/Nv/3_16.pl', 462 | '__perllib__/unicore/lib/Nv/3_4.pl', 463 | '__perllib__/unicore/lib/Nv/4.pl', 464 | '__perllib__/unicore/lib/Nv/40.pl', 465 | '__perllib__/unicore/lib/Nv/400.pl', 466 | '__perllib__/unicore/lib/Nv/4000.pl', 467 | '__perllib__/unicore/lib/Nv/40000.pl', 468 | '__perllib__/unicore/lib/Nv/5.pl', 469 | '__perllib__/unicore/lib/Nv/50.pl', 470 | '__perllib__/unicore/lib/Nv/500.pl', 471 | '__perllib__/unicore/lib/Nv/5000.pl', 472 | '__perllib__/unicore/lib/Nv/50000.pl', 473 | '__perllib__/unicore/lib/Nv/6.pl', 474 | '__perllib__/unicore/lib/Nv/60.pl', 475 | '__perllib__/unicore/lib/Nv/600.pl', 476 | '__perllib__/unicore/lib/Nv/6000.pl', 477 | '__perllib__/unicore/lib/Nv/60000.pl', 478 | '__perllib__/unicore/lib/Nv/7.pl', 479 | '__perllib__/unicore/lib/Nv/70.pl', 480 | '__perllib__/unicore/lib/Nv/700.pl', 481 | '__perllib__/unicore/lib/Nv/7000.pl', 482 | '__perllib__/unicore/lib/Nv/70000.pl', 483 | '__perllib__/unicore/lib/Nv/8.pl', 484 | '__perllib__/unicore/lib/Nv/80.pl', 485 | '__perllib__/unicore/lib/Nv/800.pl', 486 | '__perllib__/unicore/lib/Nv/8000.pl', 487 | '__perllib__/unicore/lib/Nv/80000.pl', 488 | '__perllib__/unicore/lib/Nv/9.pl', 489 | '__perllib__/unicore/lib/Nv/90.pl', 490 | '__perllib__/unicore/lib/Nv/900.pl', 491 | '__perllib__/unicore/lib/Nv/9000.pl', 492 | '__perllib__/unicore/lib/Nv/90000.pl', 493 | '__perllib__/unicore/lib/PCM/Y.pl', 494 | '__perllib__/unicore/lib/PatSyn/Y.pl', 495 | '__perllib__/unicore/lib/Perl/Alnum.pl', 496 | '__perllib__/unicore/lib/Perl/Assigned.pl', 497 | '__perllib__/unicore/lib/Perl/Blank.pl', 498 | '__perllib__/unicore/lib/Perl/Graph.pl', 499 | '__perllib__/unicore/lib/Perl/PerlWord.pl', 500 | '__perllib__/unicore/lib/Perl/PosixPun.pl', 501 | '__perllib__/unicore/lib/Perl/Print.pl', 502 | '__perllib__/unicore/lib/Perl/SpacePer.pl', 503 | '__perllib__/unicore/lib/Perl/Title.pl', 504 | '__perllib__/unicore/lib/Perl/Word.pl', 505 | '__perllib__/unicore/lib/Perl/XPosixPu.pl', 506 | '__perllib__/unicore/lib/Perl/_PerlAny.pl', 507 | '__perllib__/unicore/lib/Perl/_PerlCh2.pl', 508 | '__perllib__/unicore/lib/Perl/_PerlCha.pl', 509 | '__perllib__/unicore/lib/Perl/_PerlFol.pl', 510 | '__perllib__/unicore/lib/Perl/_PerlIDC.pl', 511 | '__perllib__/unicore/lib/Perl/_PerlIDS.pl', 512 | '__perllib__/unicore/lib/Perl/_PerlIsI.pl', 513 | '__perllib__/unicore/lib/Perl/_PerlNch.pl', 514 | '__perllib__/unicore/lib/Perl/_PerlPat.pl', 515 | '__perllib__/unicore/lib/Perl/_PerlPr2.pl', 516 | '__perllib__/unicore/lib/Perl/_PerlPro.pl', 517 | '__perllib__/unicore/lib/Perl/_PerlQuo.pl', 518 | '__perllib__/unicore/lib/QMark/Y.pl', 519 | '__perllib__/unicore/lib/SB/AT.pl', 520 | '__perllib__/unicore/lib/SB/CL.pl', 521 | '__perllib__/unicore/lib/SB/EX.pl', 522 | '__perllib__/unicore/lib/SB/FO.pl', 523 | '__perllib__/unicore/lib/SB/LE.pl', 524 | '__perllib__/unicore/lib/SB/LO.pl', 525 | '__perllib__/unicore/lib/SB/NU.pl', 526 | '__perllib__/unicore/lib/SB/SC.pl', 527 | '__perllib__/unicore/lib/SB/ST.pl', 528 | '__perllib__/unicore/lib/SB/Sp.pl', 529 | '__perllib__/unicore/lib/SB/UP.pl', 530 | '__perllib__/unicore/lib/SB/XX.pl', 531 | '__perllib__/unicore/lib/SD/Y.pl', 532 | '__perllib__/unicore/lib/STerm/Y.pl', 533 | '__perllib__/unicore/lib/Sc/Arab.pl', 534 | '__perllib__/unicore/lib/Sc/Beng.pl', 535 | '__perllib__/unicore/lib/Sc/Cprt.pl', 536 | '__perllib__/unicore/lib/Sc/Cyrl.pl', 537 | '__perllib__/unicore/lib/Sc/Deva.pl', 538 | '__perllib__/unicore/lib/Sc/Dupl.pl', 539 | '__perllib__/unicore/lib/Sc/Geor.pl', 540 | '__perllib__/unicore/lib/Sc/Glag.pl', 541 | '__perllib__/unicore/lib/Sc/Gong.pl', 542 | '__perllib__/unicore/lib/Sc/Gonm.pl', 543 | '__perllib__/unicore/lib/Sc/Gran.pl', 544 | '__perllib__/unicore/lib/Sc/Grek.pl', 545 | '__perllib__/unicore/lib/Sc/Gujr.pl', 546 | '__perllib__/unicore/lib/Sc/Guru.pl', 547 | '__perllib__/unicore/lib/Sc/Han.pl', 548 | '__perllib__/unicore/lib/Sc/Hang.pl', 549 | '__perllib__/unicore/lib/Sc/Hira.pl', 550 | '__perllib__/unicore/lib/Sc/Kana.pl', 551 | '__perllib__/unicore/lib/Sc/Knda.pl', 552 | '__perllib__/unicore/lib/Sc/Latn.pl', 553 | '__perllib__/unicore/lib/Sc/Limb.pl', 554 | '__perllib__/unicore/lib/Sc/Linb.pl', 555 | '__perllib__/unicore/lib/Sc/Mlym.pl', 556 | '__perllib__/unicore/lib/Sc/Mong.pl', 557 | '__perllib__/unicore/lib/Sc/Mult.pl', 558 | '__perllib__/unicore/lib/Sc/Orya.pl', 559 | '__perllib__/unicore/lib/Sc/Sinh.pl', 560 | '__perllib__/unicore/lib/Sc/Syrc.pl', 561 | '__perllib__/unicore/lib/Sc/Taml.pl', 562 | '__perllib__/unicore/lib/Sc/Telu.pl', 563 | '__perllib__/unicore/lib/Sc/Zinh.pl', 564 | '__perllib__/unicore/lib/Sc/Zyyy.pl', 565 | '__perllib__/unicore/lib/Scx/Adlm.pl', 566 | '__perllib__/unicore/lib/Scx/Arab.pl', 567 | '__perllib__/unicore/lib/Scx/Armn.pl', 568 | '__perllib__/unicore/lib/Scx/Beng.pl', 569 | '__perllib__/unicore/lib/Scx/Bhks.pl', 570 | '__perllib__/unicore/lib/Scx/Bopo.pl', 571 | '__perllib__/unicore/lib/Scx/Cakm.pl', 572 | '__perllib__/unicore/lib/Scx/Cham.pl', 573 | '__perllib__/unicore/lib/Scx/Copt.pl', 574 | '__perllib__/unicore/lib/Scx/Cprt.pl', 575 | '__perllib__/unicore/lib/Scx/Cyrl.pl', 576 | '__perllib__/unicore/lib/Scx/Deva.pl', 577 | '__perllib__/unicore/lib/Scx/Diak.pl', 578 | '__perllib__/unicore/lib/Scx/Dupl.pl', 579 | '__perllib__/unicore/lib/Scx/Ethi.pl', 580 | '__perllib__/unicore/lib/Scx/Geor.pl', 581 | '__perllib__/unicore/lib/Scx/Glag.pl', 582 | '__perllib__/unicore/lib/Scx/Gong.pl', 583 | '__perllib__/unicore/lib/Scx/Gonm.pl', 584 | '__perllib__/unicore/lib/Scx/Gran.pl', 585 | '__perllib__/unicore/lib/Scx/Grek.pl', 586 | '__perllib__/unicore/lib/Scx/Gujr.pl', 587 | '__perllib__/unicore/lib/Scx/Guru.pl', 588 | '__perllib__/unicore/lib/Scx/Han.pl', 589 | '__perllib__/unicore/lib/Scx/Hang.pl', 590 | '__perllib__/unicore/lib/Scx/Hebr.pl', 591 | '__perllib__/unicore/lib/Scx/Hira.pl', 592 | '__perllib__/unicore/lib/Scx/Hmng.pl', 593 | '__perllib__/unicore/lib/Scx/Hmnp.pl', 594 | '__perllib__/unicore/lib/Scx/Kana.pl', 595 | '__perllib__/unicore/lib/Scx/Khar.pl', 596 | '__perllib__/unicore/lib/Scx/Khmr.pl', 597 | '__perllib__/unicore/lib/Scx/Khoj.pl', 598 | '__perllib__/unicore/lib/Scx/Knda.pl', 599 | '__perllib__/unicore/lib/Scx/Kthi.pl', 600 | '__perllib__/unicore/lib/Scx/Lana.pl', 601 | '__perllib__/unicore/lib/Scx/Lao.pl', 602 | '__perllib__/unicore/lib/Scx/Latn.pl', 603 | '__perllib__/unicore/lib/Scx/Limb.pl', 604 | '__perllib__/unicore/lib/Scx/Lina.pl', 605 | '__perllib__/unicore/lib/Scx/Linb.pl', 606 | '__perllib__/unicore/lib/Scx/Mlym.pl', 607 | '__perllib__/unicore/lib/Scx/Mong.pl', 608 | '__perllib__/unicore/lib/Scx/Mult.pl', 609 | '__perllib__/unicore/lib/Scx/Mymr.pl', 610 | '__perllib__/unicore/lib/Scx/Nand.pl', 611 | '__perllib__/unicore/lib/Scx/Nko.pl', 612 | '__perllib__/unicore/lib/Scx/Orya.pl', 613 | '__perllib__/unicore/lib/Scx/Phlp.pl', 614 | '__perllib__/unicore/lib/Scx/Rohg.pl', 615 | '__perllib__/unicore/lib/Scx/Shrd.pl', 616 | '__perllib__/unicore/lib/Scx/Sind.pl', 617 | '__perllib__/unicore/lib/Scx/Sinh.pl', 618 | '__perllib__/unicore/lib/Scx/Syrc.pl', 619 | '__perllib__/unicore/lib/Scx/Tagb.pl', 620 | '__perllib__/unicore/lib/Scx/Takr.pl', 621 | '__perllib__/unicore/lib/Scx/Talu.pl', 622 | '__perllib__/unicore/lib/Scx/Taml.pl', 623 | '__perllib__/unicore/lib/Scx/Tang.pl', 624 | '__perllib__/unicore/lib/Scx/Telu.pl', 625 | '__perllib__/unicore/lib/Scx/Thaa.pl', 626 | '__perllib__/unicore/lib/Scx/Tibt.pl', 627 | '__perllib__/unicore/lib/Scx/Tirh.pl', 628 | '__perllib__/unicore/lib/Scx/Vith.pl', 629 | '__perllib__/unicore/lib/Scx/Xsux.pl', 630 | '__perllib__/unicore/lib/Scx/Yezi.pl', 631 | '__perllib__/unicore/lib/Scx/Yi.pl', 632 | '__perllib__/unicore/lib/Scx/Zinh.pl', 633 | '__perllib__/unicore/lib/Scx/Zyyy.pl', 634 | '__perllib__/unicore/lib/Scx/Zzzz.pl', 635 | '__perllib__/unicore/lib/Term/Y.pl', 636 | '__perllib__/unicore/lib/UIdeo/Y.pl', 637 | '__perllib__/unicore/lib/Upper/Y.pl', 638 | '__perllib__/unicore/lib/VS/Y.pl', 639 | '__perllib__/unicore/lib/Vo/R.pl', 640 | '__perllib__/unicore/lib/Vo/Tr.pl', 641 | '__perllib__/unicore/lib/Vo/Tu.pl', 642 | '__perllib__/unicore/lib/Vo/U.pl', 643 | '__perllib__/unicore/lib/WB/EX.pl', 644 | '__perllib__/unicore/lib/WB/Extend.pl', 645 | '__perllib__/unicore/lib/WB/FO.pl', 646 | '__perllib__/unicore/lib/WB/HL.pl', 647 | '__perllib__/unicore/lib/WB/KA.pl', 648 | '__perllib__/unicore/lib/WB/LE.pl', 649 | '__perllib__/unicore/lib/WB/MB.pl', 650 | '__perllib__/unicore/lib/WB/ML.pl', 651 | '__perllib__/unicore/lib/WB/MN.pl', 652 | '__perllib__/unicore/lib/WB/NU.pl', 653 | '__perllib__/unicore/lib/WB/WSegSpac.pl', 654 | '__perllib__/unicore/lib/WB/XX.pl', 655 | '__perllib__/unicore/lib/XIDC/Y.pl', 656 | '__perllib__/unicore/lib/XIDS/Y.pl', 657 | '__perllib__/utf8.pm', 658 | '__perllib__/vars.pm', 659 | '__perllib__/warnings.pm', 660 | '__perllib__/warnings/register.pm', 661 | ); 662 | 663 | my %defconfig = ( 664 | cosmo_remotes => { 665 | origin => 'https://github.com/G4Vi/cosmopolitan', 666 | upstream => 'https://github.com/jart/cosmopolitan', 667 | }, 668 | perl_remotes => { 669 | origin => 'https://github.com/G4Vi/perl5', 670 | }, 671 | apperl_configs => { 672 | 'nobuild-v0.1.0' => { 673 | desc => 'use nobuild as base instead of this', 674 | dest => 'perl-nobuild.com', 675 | MANIFEST => ['lib', 'bin'], 676 | zip_extra_files => {}, 677 | nobuild_perl_bin => ['src/perl.com', $^X], 678 | }, 679 | 'v5.36.0-full-v0.1.0-vista' => { 680 | desc => 'Full perl v5.36.0, but with non-standard Cosmopolitan Libc that still supports vista', 681 | perl_id => 'b22da6b83c37604132694ead0bdcf61690f74a53', 682 | cosmo_id => '9c5a7795add7add5a214afce27d896084e0861c5', 683 | cosmo_mode => '', 684 | cosmo_ape_loader => 'ape-no-modify-self.o', 685 | dest => 'perl-vista.com', 686 | perl_flags => ['-Dprefix=/zip', '-Uversiononly', '-Dmyhostname=cosmo', '-Dmydomain=invalid'], 687 | perl_extra_flags => ['-Doptimize=-Os', '-de'], 688 | MANIFEST => ['lib', 'bin'], 689 | 'include_Perl-Dist-APPerl' => 1, 690 | perl_repo_files => {}, 691 | zip_extra_files => {}, 692 | }, 693 | 'v5.36.0-small-v0.1.0-vista' => { 694 | desc => 'small perl v5.36.0, but with non-standard Cosmopolitan Libc that still supports vista', 695 | base => 'v5.36.0-full-v0.1.0-vista', 696 | perl_onlyextensions => [qw(Cwd Fcntl File/Glob Hash/Util IO List/Util POSIX Socket attributes re)], 697 | MANIFEST => \@smallmanifest, 698 | 'include_Perl-Dist-APPerl' => 0, 699 | dest => 'perl-small-vista.com', 700 | }, 701 | 'full-vista' => { desc => 'moving target: full for vista', base => 'v5.36.0-full-v0.1.0-vista', perl_id => '239a05bbef291b8de3309c95852d41fc027cacab', cosmo_id => 'fea68b142e59b5861fe09375eb5bcb256b69b70e', '+perl_extra_flags' => ['-Dprivlib=/zip/lib/perl5', '-Darchlib=/zip/lib/perl5/x86_64-cosmo', '-Dsitelib=/zip/lib/perl5/site_perl', '-Dsitearch=/zip/lib/perl5/site_perl/x86_64-cosmo']}, 702 | 'small-vista' => { desc => 'moving target: small for vista', base => 'v5.36.0-small-v0.1.0-vista', perl_id => '239a05bbef291b8de3309c95852d41fc027cacab', cosmo_id => 'fea68b142e59b5861fe09375eb5bcb256b69b70e', '+perl_extra_flags' => ['-Dprivlib=/zip/lib/perl5', '-Darchlib=/zip/lib/perl5/x86_64-cosmo', '-Dsitelib=/zip/lib/perl5/site_perl', '-Dsitearch=/zip/lib/perl5/site_perl/x86_64-cosmo']}, 703 | 'full' => { 704 | desc => 'moving target: full', 705 | perl_flags => ['-Dprefix=/zip', '-Uversiononly', '-Dmyhostname=cosmo', '-Dmydomain=invalid'], 706 | perl_extra_flags => ['-Doptimize=-Os', '-de', '-Dprivlib=/zip/lib/perl5', '-Darchlib=/zip/lib/perl5/x86_64-cosmo', '-Dsitelib=/zip/lib/perl5/site_perl', '-Dsitearch=/zip/lib/perl5/site_perl/x86_64-cosmo'], 707 | MANIFEST => ['lib', 'bin'], 708 | 'include_Perl-Dist-APPerl' => 1, 709 | perl_repo_files => {}, 710 | zip_extra_files => {}, 711 | cosmo3 => 1, 712 | dest => 'perl.com', 713 | perl_url => 'https://github.com/Perl/perl5/archive/refs/tags/v5.36.3.tar.gz', 714 | patches => ['__sharedir__/5.36-cosmo3.patch', '__sharedir__/5.36-cosmo-apperl.patch'], 715 | install_modules => [], 716 | }, 717 | 'small' => { 718 | desc => 'moving target: small', 719 | base => 'full', 720 | perl_onlyextensions => [qw(Cwd ErrnoRuntime Fcntl File/Glob Hash/Util IO List/Util POSIX Socket attributes re)], 721 | MANIFEST => \@smallmanifest, 722 | 'include_Perl-Dist-APPerl' => 0, 723 | dest => 'perl-small.com', 724 | install_modules => [], 725 | }, 726 | 'nobuild' => { 727 | desc => 'base nobuild config', 728 | dest => 'perl-nobuild.com', 729 | MANIFEST => ['lib', 'bin'], 730 | zip_extra_files => {}, 731 | nobuild_perl_bin => ['src/perl.com', $^X], 732 | }, 733 | # development configs 734 | perl_cosmo_dev => { 735 | desc => "For developing cosmo platform perl without apperl additions", 736 | base => 'full', 737 | perl_id => 'v5.36.3', 738 | perl_url => undef, 739 | patches => ['__sharedir__/5.36-cosmo3.patch'], 740 | }, 741 | perl_apperl_dev => { 742 | desc => "For developing apperl", 743 | base => 'perl_cosmo3_dev', 744 | '+patches' => ['__sharedir__/5.36-cosmo-apperl.patch'], 745 | } 746 | } 747 | ); 748 | $defconfig{defaultconfig} = 'full'; 749 | 750 | my $projectconfig = _load_json(PROJECT_FILE); 751 | if($projectconfig) { 752 | foreach my $projkey (keys %$projectconfig) { 753 | if($projkey ne 'apperl_configs') { 754 | $defconfig{$projkey} = $projectconfig->{$projkey}; 755 | } 756 | else { 757 | $defconfig{$projkey} = {%{$defconfig{$projkey}}, %{$projectconfig->{$projkey}}}; 758 | } 759 | } 760 | } 761 | return \%defconfig; 762 | } 763 | 764 | sub _build_def_config { 765 | return { 766 | base => ($_[0] // 'nobuild'), 767 | desc => 'description of this config', 768 | dest => 'perl.com' 769 | }; 770 | } 771 | 772 | sub Init { 773 | my ($defaultconfig, $base) = @_; 774 | # validate 775 | die "Cannot create project config, it already exists ".PROJECT_FILE if(-e PROJECT_FILE); 776 | my $Configs = _load_apperl_configs(); 777 | if(defined $base) { 778 | $defaultconfig or die "Cannot set base without name for new config"; 779 | if(exists $Configs->{apperl_configs}{$defaultconfig}) { 780 | die "Cannot set base for $defaultconfig, $defaultconfig already exists "; 781 | } 782 | exists $Configs->{apperl_configs}{$base} or die "base config $base does not exist"; 783 | } 784 | 785 | # create project config 786 | my %jsondata = ( 'defaultconfig' => ($defaultconfig // 'nobuild')); 787 | if($defaultconfig && ! exists $Configs->{apperl_configs}{$defaultconfig}) { 788 | $jsondata{apperl_configs} = { 789 | $defaultconfig => _build_def_config($base), 790 | }; 791 | } 792 | print "writing new project\n"; 793 | _write_json(PROJECT_FILE, \%jsondata); 794 | 795 | # checkout default config 796 | Checkout($jsondata{defaultconfig}); 797 | } 798 | 799 | sub NewConfig { 800 | my ($name, $base) = @_; 801 | $name or die "Name required to add new config"; 802 | my $Configs = _load_apperl_configs(); 803 | ! exists $Configs->{apperl_configs}{$name} or die "Cannot create already existing config"; 804 | if(defined $base) { 805 | exists $Configs->{apperl_configs}{$base} or die "base config $base does not exist"; 806 | } 807 | my $projectconfig = _load_json(PROJECT_FILE) or die "project file must already exist"; 808 | $projectconfig->{apperl_configs}{$name} = _build_def_config($base); 809 | print "rewriting project\n"; 810 | _write_json(PROJECT_FILE, $projectconfig); 811 | } 812 | 813 | sub _install_cosmocc { 814 | my ($SiteConfig, $version) = @_; 815 | $version //= '3.3.10'; 816 | my $cosmocc = SITE_REPO_DIR."/cosmocc"; 817 | print "rm -rf $cosmocc\n"; 818 | remove_tree($cosmocc); 819 | print "mkdir -p $cosmocc\n"; 820 | make_path($cosmocc); 821 | print "cd $cosmocc\n"; 822 | my $before = getcwd(); 823 | chdir($cosmocc) or die "Failed to chdir $cosmocc"; 824 | my $filename = "cosmocc-$version.zip"; 825 | _command_or_die('wget', "https://cosmo.zip/pub/cosmocc/$filename"); 826 | _command_or_die('unzip', $filename); 827 | chdir($before) or die "error resetting directory"; 828 | $SiteConfig->{cosmocc} = $cosmocc; 829 | make_path(SITE_CONFIG_DIR); 830 | _write_json(SITE_CONFIG_FILE, $SiteConfig); 831 | } 832 | 833 | sub InstallBuildDeps { 834 | my ($perlrepo, $cosmorepo) = @_; 835 | my $SiteConfig = _load_json(SITE_CONFIG_FILE); 836 | $SiteConfig //= {}; 837 | 838 | # if a repo is not set, set one up by default 839 | if(!exists $SiteConfig->{perl_repo} && !$perlrepo) { 840 | $perlrepo = SITE_REPO_DIR."/perl5"; 841 | _setup_repo($perlrepo, _load_apperl_configs()->{perl_remotes}); 842 | print "apperlm install-build-deps: setup perl repo\n"; 843 | } 844 | if(!exists $SiteConfig->{cosmo_repo} && !$cosmorepo) { 845 | $cosmorepo = SITE_REPO_DIR."/cosmopolitan"; 846 | _setup_repo( $cosmorepo, _load_apperl_configs()->{cosmo_remotes}); 847 | print "apperlm install-build-deps: setup cosmo repo\n"; 848 | } 849 | 850 | # (re)write site config 851 | $perlrepo //= $SiteConfig->{perl_repo}; 852 | $cosmorepo //= $SiteConfig->{cosmo_repo}; 853 | $SiteConfig->{perl_repo} = abs_path($perlrepo); 854 | $SiteConfig->{cosmo_repo} = abs_path($cosmorepo); 855 | make_path(SITE_CONFIG_DIR); 856 | _write_json(SITE_CONFIG_FILE, $SiteConfig); 857 | print "apperlm install-build-deps: wrote site config to ".SITE_CONFIG_FILE."\n"; 858 | } 859 | 860 | sub _remove_arr_items_from_arr { 861 | my ($src, $toremove) = @_; 862 | my @remove = @{$toremove}; 863 | foreach my $srcindex (reverse 0..$#{$src}) { 864 | for my $removeindex (reverse 0..$#remove) { 865 | if ($src->[$srcindex] eq $remove[$removeindex]) { 866 | splice(@$src, $srcindex, 1); 867 | return if (scalar(@remove) == 1); 868 | splice(@remove, $removeindex, 1); 869 | last; 870 | } 871 | } 872 | } 873 | } 874 | 875 | sub Status { 876 | my $Configs = _load_apperl_configs(); 877 | my @configlist = sort(keys %{$Configs->{apperl_configs}}); 878 | my $UserProjectConfig = _load_user_project_config(); 879 | my $CurAPPerlName; 880 | if($UserProjectConfig) { 881 | if(exists $UserProjectConfig->{current_apperl}) { 882 | $CurAPPerlName = $UserProjectConfig->{current_apperl}; 883 | exists $Configs->{apperl_configs}{$CurAPPerlName} or die("non-existent apperl config $CurAPPerlName in user project config"); 884 | } 885 | } 886 | if(!defined $CurAPPerlName && exists $Configs->{'defaultconfig'}) { 887 | $CurAPPerlName = $Configs->{'defaultconfig'}; 888 | exists $Configs->{apperl_configs}{$CurAPPerlName} or die("non-existent default apperl config $CurAPPerlName"); 889 | } 890 | 891 | my @projectitems; 892 | my $projectconfig = _load_json(PROJECT_FILE); 893 | if($projectconfig && exists $projectconfig->{apperl_configs}) { 894 | @projectitems = sort (keys %{$projectconfig->{apperl_configs}}); 895 | _remove_arr_items_from_arr(\@configlist, \@projectitems); 896 | } 897 | my @rolling = grep(/^(full|small|nobuild)$/, @configlist); 898 | { 899 | my %preferences = ( full => 0, small => 1, nobuild => 2); 900 | @rolling = sort {$preferences{$a} <=> $preferences{$b}} @rolling; 901 | } 902 | _remove_arr_items_from_arr(\@configlist, \@rolling); 903 | my @deprecated = grep(/(\-vista|v0\.1\.0)$/, @configlist); 904 | _remove_arr_items_from_arr(\@configlist, \@deprecated); 905 | my @internal = grep(/^(dontuse_threads|perl_cosmo_dev|perl_apperl_dev|dbg)$/, @configlist); 906 | _remove_arr_items_from_arr(\@configlist, \@internal); 907 | my @stable = grep( /v\d+\.\d+\.\d+$/, @configlist); 908 | _remove_arr_items_from_arr(\@configlist, \@stable); 909 | my @categories = ( 910 | ['PROJECT', \@projectitems], 911 | ['STABLE', \@stable], 912 | ['ROLLING', \@rolling], 913 | ['DEPRECATED', \@deprecated], 914 | ['UNSTABLE/INTERNAL', \@internal], 915 | ['UNKNOWN', \@configlist] 916 | ); 917 | foreach my $cat (@categories) { 918 | foreach my $item (@{$cat->[1]}) { 919 | print (sprintf "%s %-30.30s | %-17.17s |%s\n", $CurAPPerlName && ($item eq $CurAPPerlName) ? '*' : ' ', $item, $cat->[0], ($Configs->{apperl_configs}{$item}{desc} // '')); 920 | } 921 | } 922 | } 923 | 924 | # unfortunately this needs to be called in several places to try to keep them in sync 925 | # as perl's make trips up when trying to build an symlinked extension 926 | sub _install_perl_src_files { 927 | my ($itemconfig, $perl_build_dir) = @_; 928 | foreach my $dest (keys %{$itemconfig->{perl_repo_files}}) { 929 | foreach my $file (@{$itemconfig->{perl_repo_files}{$dest}}) { 930 | _copy_recursive(START_WD."/$file", "$perl_build_dir/$dest"); 931 | } 932 | } 933 | } 934 | 935 | sub Checkout { 936 | my ($cfgname) = @_; 937 | my $UserProjectConfig = _load_user_project_config(); 938 | if($UserProjectConfig) { 939 | delete $UserProjectConfig->{nobuild_perl_bin}; 940 | } 941 | else { 942 | $UserProjectConfig = {}; 943 | } 944 | $UserProjectConfig->{apperl_output} //= PROJECT_TMP_DIR."/o"; 945 | $UserProjectConfig->{current_apperl} = $cfgname; 946 | my $itemconfig = _load_apperl_config(_load_apperl_configs()->{apperl_configs}, $cfgname); 947 | print Dumper($itemconfig); 948 | if(! exists $itemconfig->{nobuild_perl_bin}) { 949 | my $SiteConfig = _load_valid_site_config($itemconfig->{cosmo3}); 950 | if(! $itemconfig->{cosmo3}) { 951 | print "cd ".$SiteConfig->{cosmo_repo}."\n"; 952 | chdir($SiteConfig->{cosmo_repo}) or die "Failed to enter cosmo repo"; 953 | _command_or_die('git', 'checkout', $itemconfig->{cosmo_id}); 954 | } 955 | $UserProjectConfig->{configs}{$cfgname}{perl_build_dir} //= $SiteConfig->{perl_repo} if !$itemconfig->{perl_url}; 956 | $UserProjectConfig->{configs}{$cfgname}{perl_build_dir} //= "$UserProjectConfig->{apperl_output}/$cfgname/tmp/perl5"; 957 | my $perl_build_dir = $UserProjectConfig->{configs}{$cfgname}{perl_build_dir}; 958 | if (! $itemconfig->{perl_url}) { 959 | -d $perl_build_dir or die $perl_build_dir .' is not directory'; 960 | print "cd ".$perl_build_dir."\n"; 961 | chdir($perl_build_dir) or die "Failed to enter perl repo"; 962 | print "make veryclean\n"; 963 | system("make", "veryclean"); 964 | foreach my $todelete ('miniperl.com', 'perl.com', 'miniperl.elf', 'miniperl.com.dbg', 'perl.elf', 'perl.com.dbg') { 965 | print "rm $todelete\n"; 966 | unlink($todelete) || $!{ENOENT} or die "failed to delete $todelete"; 967 | } 968 | _command_or_die('git', 'checkout', '-f', $itemconfig->{perl_id}); 969 | _command_or_die('git', 'clean', '-f', '-e.vscode', '-d'); 970 | $itemconfig->{patches} //= []; 971 | } else { 972 | my $tarball_name = basename($itemconfig->{perl_url}); 973 | my $download_dir = $UserProjectConfig->{apperl_output}; 974 | print "mkdir -p $download_dir\n"; 975 | make_path($download_dir); 976 | chdir($download_dir) or die "Failed to enter download dir"; 977 | if (! -f $tarball_name) { 978 | _command_or_die('wget', $itemconfig->{perl_url}); 979 | } 980 | _command_or_die('tar', '-xf', $tarball_name); 981 | print "rm -rf $perl_build_dir\n"; 982 | remove_tree($perl_build_dir); 983 | my ($version) = $tarball_name =~ /^v(\d+\.\d+\.\d+)\.tar/; 984 | my $perl_build_dir_dir = dirname($perl_build_dir); 985 | print "mkdir -p $perl_build_dir_dir\n"; 986 | make_path($perl_build_dir_dir); 987 | my $tomove = "perl5-$version"; 988 | print "mv $tomove $perl_build_dir\n"; 989 | move($tomove, $perl_build_dir) or die "Failed to move perl src"; 990 | chdir($perl_build_dir) or die "Failed to enter perl build_dir"; 991 | } 992 | foreach my $patch (@{$itemconfig->{patches}}) { 993 | my $realpatch = _fix_bases($patch, {__sharedir__ => SHARE_DIR}); 994 | # can't `git apply` to ignored files within a git repository :( 995 | _cmdinputfile_or_die('patch', '-p1', $realpatch); 996 | } 997 | print "cd ".START_WD."\n"; 998 | chdir(START_WD) or die "Failed to restore cwd"; 999 | _install_perl_src_files($itemconfig, $perl_build_dir); 1000 | } 1001 | else { 1002 | my $validperl; 1003 | foreach my $perlbin (@{$itemconfig->{nobuild_perl_bin}}) { 1004 | print "perlbin $perlbin\n"; 1005 | if(-f $perlbin) { 1006 | if(( $perlbin eq $^X) && (! -d '/zip')) { 1007 | print "skipping $perlbin, it appears to not be APPerl\n"; 1008 | next; 1009 | } 1010 | $validperl = $perlbin; 1011 | last; 1012 | } 1013 | } 1014 | $validperl or die "no valid perl found to use for nobuild config"; 1015 | $validperl = abs_path($validperl); 1016 | $validperl or die "no valid perl found to use for nobuild config"; 1017 | $UserProjectConfig->{nobuild_perl_bin} = $validperl; 1018 | print "Checkout UserProjectConfig to nobuild_perl-bin to $validperl\n"; 1019 | } 1020 | _write_user_project_config($UserProjectConfig); 1021 | print "$0: Successfully switched to $cfgname\n"; 1022 | } 1023 | 1024 | sub Configure { 1025 | my ($UserProjectConfig, $CurAPPerlName, $itemconfig) = _load_valid_configs() or die "cannot Configure without valid UserProjectConfig"; 1026 | ! exists $UserProjectConfig->{nobuild_perl_bin} or die "nobuild perl cannot be configured"; 1027 | my $perl_build_dir = $UserProjectConfig->{configs}{$CurAPPerlName}{perl_build_dir}; 1028 | $perl_build_dir && -d $perl_build_dir or die "$perl_build_dir is not a directory"; 1029 | _install_perl_src_files($itemconfig, $perl_build_dir); 1030 | my $SiteConfig = _load_valid_site_config($itemconfig->{cosmo3}); 1031 | if(! $itemconfig->{cosmo3}) { 1032 | # build toolchain 1033 | _command_or_die('make', '-C', $SiteConfig->{cosmo_repo}, '-j', 'toolchain', 'MODE=', 'ARCH=x86_64'); 1034 | # build cosmo 1035 | print "$0: Building cosmo, COSMO_MODE=$itemconfig->{cosmo_mode} COSMO_APE_LOADER=$itemconfig->{cosmo_ape_loader}\n"; 1036 | _command_or_die('make', '-C', $SiteConfig->{cosmo_repo}, '-j4', "MODE=$itemconfig->{cosmo_mode}", 1037 | "o/$itemconfig->{cosmo_mode}/cosmopolitan.a", 1038 | "o/$itemconfig->{cosmo_mode}/libc/crt/crt.o", 1039 | "o/$itemconfig->{cosmo_mode}/ape/public/ape.lds", 1040 | "o/$itemconfig->{cosmo_mode}/ape/$itemconfig->{cosmo_ape_loader}", 1041 | ); 1042 | $ENV{COSMO_MODE} = $itemconfig->{cosmo_mode}; 1043 | $ENV{COSMO_APE_LOADER} = $itemconfig->{cosmo_ape_loader}; 1044 | $ENV{COSMO_REPO} = $SiteConfig->{cosmo_repo}; 1045 | } else { 1046 | $ENV{COSMOCC} = $SiteConfig->{cosmocc}; 1047 | } 1048 | 1049 | # Finally Configure perl 1050 | print "cd $perl_build_dir\n"; 1051 | chdir($perl_build_dir) or die "Failed to enter perl repo"; 1052 | my @onlyextensions = (); 1053 | push @onlyextensions, ("-Donlyextensions= ".join(' ', sort @{$itemconfig->{perl_onlyextensions}}).' ') if(exists $itemconfig->{perl_onlyextensions}); 1054 | _command_or_die('sh', 'Configure', @{$itemconfig->{perl_flags}}, @onlyextensions, @{$itemconfig->{perl_extra_flags}}, @_); 1055 | print "$0: Configure successful, time for apperlm build\n"; 1056 | } 1057 | 1058 | sub _fix_bases { 1059 | my ($in, $aliasmap) = @_; 1060 | foreach my $key (keys %{$aliasmap}) { 1061 | $in =~ s/^$key/$aliasmap->{$key}/; 1062 | } 1063 | return $in; 1064 | } 1065 | 1066 | # system is pretty broken on APPerl when running on Windows 1067 | # let's search PATH ourselves ... 1068 | sub _find_zip { 1069 | if(($^O ne 'cosmo') || (! -f '/C/Windows/System32/cmd.exe')) { 1070 | return 'zip'; 1071 | } 1072 | else { 1073 | foreach my $dir (split(':', $ENV{PATH})) { 1074 | my $zippath = "$dir/zip.exe"; 1075 | return $zippath if(-f $zippath); 1076 | } 1077 | } 1078 | die("Failed to find zip.exe, did you download Info-Zip and add the folder containing zip.exe to \%PATH\%?"); 1079 | } 1080 | 1081 | sub Build { 1082 | my ($zippath) = @_; 1083 | my ($UserProjectConfig, $CurAPPerlName, $itemconfig) = _load_valid_configs() or die "cannot Build without valid UserProjectConfig"; 1084 | my $startdir = abs_path('./'); 1085 | 1086 | my $PERL_APE; 1087 | my @perl_config_cmd; 1088 | # build cosmo perl if this isn't a nobuild config 1089 | if(! exists $UserProjectConfig->{nobuild_perl_bin}){ 1090 | my $SiteConfig = _load_valid_site_config($itemconfig->{cosmo3}); 1091 | my $perl_build_dir = $UserProjectConfig->{configs}{$CurAPPerlName}{perl_build_dir}; 1092 | $perl_build_dir && -d $perl_build_dir or die "$perl_build_dir is not a directory"; 1093 | _install_perl_src_files($itemconfig, $perl_build_dir); 1094 | print "cd $perl_build_dir\n"; 1095 | chdir($perl_build_dir) or die "Failed to enter perl repo"; 1096 | _command_or_die('make'); 1097 | $PERL_APE = "$perl_build_dir/perl.com"; 1098 | @perl_config_cmd = ('./perl', '-Ilib'); 1099 | } 1100 | else { 1101 | $PERL_APE = $UserProjectConfig->{nobuild_perl_bin}; 1102 | @perl_config_cmd = ($PERL_APE); 1103 | } 1104 | 1105 | # prepare for install and pack 1106 | -f $PERL_APE or die "apperlm build: perl ape not found"; 1107 | my $OUTPUTDIR = "$UserProjectConfig->{apperl_output}/$CurAPPerlName/o"; 1108 | if(-d $OUTPUTDIR) { 1109 | print "rm -rf $OUTPUTDIR\n"; 1110 | remove_tree($OUTPUTDIR); 1111 | } 1112 | my $TEMPDIR = "$OUTPUTDIR/tmp"; 1113 | print "mkdir -p $TEMPDIR\n"; 1114 | make_path($TEMPDIR); 1115 | my %proxyConfig; 1116 | foreach my $item (qw(prefix version archname cc installprivlib installarchlib installsitelib installsitearch installprefixexp installbin installman1dir installman3dir)) { 1117 | $proxyConfig{$item} = _cmdoutput_or_die(@perl_config_cmd, '-e', "use Config; print \$Config{$item}"); 1118 | } 1119 | my %aliasmap = ( 1120 | '__perllib__' => $proxyConfig{installprivlib}, 1121 | '__perlarchlib__' => $proxyConfig{installarchlib}, 1122 | '__sitelib__' => $proxyConfig{installsitelib}, 1123 | '__sitearchlib__' => $proxyConfig{installsitearch} 1124 | ); 1125 | foreach my $libdir (keys %aliasmap) { 1126 | $aliasmap{$libdir} =~ s/$proxyConfig{installprefixexp}\///; 1127 | } 1128 | my @zipfiles = map { _fix_bases($_, \%aliasmap) } @{$itemconfig->{MANIFEST}}; 1129 | my $ZIP_ROOT = "$TEMPDIR$proxyConfig{installprefixexp}"; 1130 | 1131 | # install cosmo perl if this isn't a nobuild config 1132 | if(! exists $UserProjectConfig->{nobuild_perl_bin}){ 1133 | _command_or_die('make', "DESTDIR=$TEMPDIR", 'install'); 1134 | my @toremove = ("$TEMPDIR$proxyConfig{installbin}/perl", "$TEMPDIR$proxyConfig{installbin}/perl$proxyConfig{version}"); 1135 | print 'rm '.join(' ', @toremove)."\n"; 1136 | unlink(@toremove) == scalar(@toremove) or die "Failed to unlink some files"; 1137 | # HACK install Devel::PPort lib as this doesn't get done for some reason 1138 | if (-f "$TEMPDIR$proxyConfig{installarchlib}/Devel/PPPort.pm") { 1139 | _copy_recursive("lib/auto/Devel/PPPort", "$TEMPDIR$proxyConfig{installarchlib}/auto/Devel"); 1140 | unlink("$TEMPDIR$proxyConfig{installarchlib}/auto/Devel/PPPort/.exists"); 1141 | } 1142 | } 1143 | else { 1144 | make_path($ZIP_ROOT); 1145 | } 1146 | 1147 | # add zip_extra_files to the tree 1148 | foreach my $destkey (keys %{$itemconfig->{zip_extra_files}}) { 1149 | my $dest = "$ZIP_ROOT/"._fix_bases($destkey, \%aliasmap); 1150 | foreach my $file (@{$itemconfig->{zip_extra_files}{$destkey}}) { 1151 | _copy_recursive($file, $dest); 1152 | } 1153 | } 1154 | 1155 | # pack 1156 | my $APPPATH = "$TEMPDIR/".basename($PERL_APE); 1157 | my $packAPE = sub { 1158 | my $copyexe = sub { 1159 | my ($srcpath, $destpath) = @_; 1160 | print "cp $srcpath $destpath\n"; 1161 | copy($srcpath, $destpath) or die "copy failed: $!"; 1162 | print "chmod 755 $destpath\n"; 1163 | chmod(0755, $destpath) or die $!; 1164 | }; 1165 | $copyexe->($PERL_APE, $APPPATH); 1166 | my $srcdbg = "$PERL_APE.dbg"; 1167 | for(1..2) { 1168 | if(-f $srcdbg) { 1169 | $copyexe->($srcdbg, "$APPPATH.dbg"); 1170 | last; 1171 | } 1172 | $srcdbg = $PERL_APE; 1173 | $srcdbg =~ s/com$/elf/; 1174 | } 1175 | if((! exists $UserProjectConfig->{nobuild_perl_bin}) || scalar(keys %{$itemconfig->{zip_extra_files}})) { 1176 | print "cd $ZIP_ROOT\n"; 1177 | chdir($ZIP_ROOT) or die "failed to enter ziproot"; 1178 | _command_or_die($zippath // _find_zip(), '-r', $APPPATH, @zipfiles); 1179 | } 1180 | }; 1181 | $packAPE->(); 1182 | 1183 | # install modules 1184 | if(exists $itemconfig->{install_modules}) { 1185 | my $perlman1 = "$TEMPDIR$proxyConfig{installman1dir}"; 1186 | my $perlman3 = "$TEMPDIR$proxyConfig{installman3dir}"; 1187 | my $perlbin = "$TEMPDIR$proxyConfig{installbin}"; 1188 | my $perllib = "$TEMPDIR$proxyConfig{installprivlib}"; 1189 | my $perlarchlib = "$TEMPDIR$proxyConfig{installarchlib}"; 1190 | my $mmopt = sub { 1191 | my @mmopt = ("PERL_LIB=$perllib", "PERL_ARCHLIB=$perlarchlib", 1192 | #"MAP_TARGET=perl.com.dbg", 1193 | "MAP_TARGET=perl.com", 1194 | "INSTALLDIRS=perl", 1195 | "INSTALLARCHLIB=$perlarchlib", 1196 | "INSTALLPRIVLIB=$perllib", 1197 | "INSTALLBIN=$perlbin", 1198 | "INSTALLSCRIPT=$perlbin", 1199 | "INSTALLMAN1DIR=$perlman1", 1200 | "INSTALLMAN3DIR=$perlman3" 1201 | ); 1202 | my $str; 1203 | $str .= qq["$_" ] foreach @mmopt; 1204 | chop $str; 1205 | return $str; 1206 | }->(); 1207 | my $mbopt = sub { 1208 | my %mbinstall_path = ( 1209 | lib => $perllib, 1210 | arch => $perlarchlib, 1211 | script => $perlbin, 1212 | bin => $perlbin, 1213 | bindoc => $perlman1, 1214 | libdoc => $perlman3 1215 | ); 1216 | my $mbopt; 1217 | foreach my $key (keys %mbinstall_path) { 1218 | $mbopt .= qq[--install_path $key=$mbinstall_path{$key} ]; 1219 | }; 1220 | chop $mbopt; 1221 | return $mbopt; 1222 | }->(); 1223 | local $ENV{PERL_MB_OPT} = $mbopt; 1224 | local $ENV{PERL_MM_OPT} = $mmopt; 1225 | local $ENV{PERL5LIB} = $perllib; 1226 | local $ENV{PERL_LOCAL_LIB_ROOT} = ''; 1227 | foreach my $module (@{$itemconfig->{install_modules}}) { 1228 | my $modulepath = "$startdir/$module"; 1229 | if(-d $modulepath) { 1230 | _copy_recursive($modulepath, $TEMPDIR); 1231 | $modulepath = "$TEMPDIR/".basename($modulepath); 1232 | } 1233 | elsif( -f _) { 1234 | _command_or_die('tar', 'xvf', $modulepath, '-C', $TEMPDIR); 1235 | $modulepath = "$TEMPDIR/".basename($modulepath); 1236 | $modulepath =~ s/\.tar.*$//; 1237 | } 1238 | else { 1239 | die "Module must be a directory or tarball"; 1240 | } 1241 | 1242 | print "cd $modulepath\n"; 1243 | chdir($modulepath) or die "Failed to enter module dir"; 1244 | # Module::Build (including installing Module::Build) 1245 | # Beware, Module::Build has no support for relinking the Perl binary like EU::MM - https://rt.cpan.org/Public/Bug/Display.html?id=47282 1246 | if(-f 'Build.PL') { 1247 | _command_or_die($APPPATH, 'Build.PL'); 1248 | _command_or_die($APPPATH, 'Build'); 1249 | _command_or_die($APPPATH, 'Build', 'install'); 1250 | } 1251 | # ExtUtils::MakeMaker 1252 | elsif( -f 'Makefile.PL') { 1253 | # build 1254 | _command_or_die($APPPATH, 'Makefile.PL'); 1255 | _command_or_die('make'); 1256 | # install into the src tree 1257 | _command_or_die('make', 'install'); 1258 | # build a new perl binary, convert to APE, and repack zip 1259 | #_command_or_die('make', 'perl.com.dbg'); 1260 | #_command_or_die(dirname($proxyConfig{cc})."/x86_64-linux-musl-objcopy", '-S', '-O', 'binary', 'perl.com.dbg', 'perl.com'); 1261 | _command_or_die('make', 'Makefile.aperl'); 1262 | # HACK, add in DynaLoader as it's missing 1263 | open(my $makefile, '<', 'Makefile.aperl') or die "failed to open Makefile.aperl"; 1264 | my @newlines = map { $_ =~ s/writemain\((grep[^\)]+\))/writemain((DynaLoader, $1)/; $_} <$makefile>; 1265 | close($makefile); 1266 | open(my $newmakefile, '>', 'Makefile.aperl') or die "failed to open Makefile.aperl for writing"; 1267 | print $newmakefile $_ foreach @newlines; 1268 | close($newmakefile); 1269 | # finally rebuild perl 1270 | _command_or_die('make', '-f', 'Makefile.aperl', 'perl.com'); 1271 | $PERL_APE = abs_path('./perl.com'); 1272 | } 1273 | else { 1274 | die "No Makefile.PL or Build.PL found, unable to install module"; 1275 | } 1276 | $packAPE->(); 1277 | } 1278 | } 1279 | 1280 | # patch default script 1281 | if(exists $itemconfig->{default_script}) { 1282 | length($itemconfig->{default_script}) <= 255 or die "default script path is too long"; 1283 | open(my $fh, '+<:raw', $APPPATH) or die "$!"; 1284 | my $fsize = (stat($fh))[7]; 1285 | my $bread = read($fh, my $outdata, $fsize); 1286 | $bread && $bread == $fsize or die "failed to read full file $APPPATH"; 1287 | my $sentinel = "APPERL_DEFAULT_SCRIPT\x00"; 1288 | my $sentinelpos = index($outdata, $sentinel); 1289 | $sentinelpos != -1 or die "Failed to find APPERL_DEFAULT_SCRIPT, is this an old APPerl binary?"; 1290 | my $patchpos = $sentinelpos+length($sentinel); 1291 | print "patching default script at $patchpos\n"; 1292 | seek($fh, $patchpos, SEEK_SET) or die "$!"; 1293 | print $fh $itemconfig->{default_script}."\0" or die "$!"; 1294 | close($fh); 1295 | } 1296 | 1297 | foreach my $file ('perl.com', 'perl.com.dbg') { 1298 | my $srcpath = "$TEMPDIR/$file"; 1299 | -e $srcpath or next; 1300 | my $destpath = "$OUTPUTDIR/$file"; 1301 | print "mv $srcpath $destpath\n"; 1302 | move($srcpath, $destpath) or die "move failed: $!"; 1303 | } 1304 | 1305 | # copy to user specified location 1306 | if(exists $itemconfig->{dest}) { 1307 | print "cd ".START_WD."\n"; 1308 | chdir(START_WD) or die "Failed to restore cwd"; 1309 | foreach my $srcfile ('perl.com', 'perl.com.dbg') { 1310 | my $destfile = $itemconfig->{dest}; 1311 | $destfile .= '.dbg' if ($srcfile =~ /dbg$/); 1312 | if (-f $destfile) { 1313 | # avoid bus error by renaming the existing executable 1314 | my $olddest = "$destfile.old"; 1315 | print "mv $destfile $olddest\n"; 1316 | move($destfile, $olddest) or die "move failed: $!"; 1317 | } 1318 | my @args = ("$UserProjectConfig->{apperl_output}/$CurAPPerlName/o/$srcfile", $destfile); 1319 | -e $args[0] or next; 1320 | print 'cp '.join(' ', @args)."\n"; 1321 | cp(@args) or die "copy failed: $!"; 1322 | } 1323 | } 1324 | } 1325 | 1326 | sub apperlm { 1327 | my $generic_usage = <<'END_USAGE'; 1328 | apperlm [...] 1329 | List of commands, try apperlm --help for info about a command 1330 | list | List available APPerl configurations 1331 | init | Create an APPerl project in the current dir 1332 | new-config | Add a new APPerl configuration to the project 1333 | checkout | Switch to another APPerl configurations 1334 | install-build-deps | Install build dependencies for APPerl 1335 | configure | `Configure` Perl (only valid with build config) 1336 | build | Build APPerl 1337 | help | Prints this message 1338 | 1339 | Actually Portable Perl Manager (apperlm) handles configuring and 1340 | building Actually Portable Perl (APPerl). See 1341 | `perldoc Perl::Dist::APPerl` for more info. 1342 | END_USAGE 1343 | my $command = shift(@_) if(@_); 1344 | $command or die($generic_usage); 1345 | if($command eq 'list') { 1346 | my $usage = <<'END_USAGE'; 1347 | apperlm list 1348 | List available APPerl configs; checks apperl-project.json and built-in 1349 | to Perl::Dist::APPerl configs. If a current config is set it is denoted 1350 | with a '*'. 1351 | END_USAGE 1352 | die($usage) if(@_); 1353 | Perl::Dist::APPerl::Status(); 1354 | } 1355 | elsif($command eq 'build') { 1356 | my $usage = <<'END_USAGE'; 1357 | apperlm build [-z|--zippath ] 1358 | -z|--zippath Path to InfoZip zip executable 1359 | Build APPerl. If the current config is a from-scratch build, you must 1360 | run `apperlm configure` first. 1361 | END_USAGE 1362 | my $zippath; 1363 | my $help; 1364 | GetOptionsFromArray(\@_, "zippath|z=s" => \$zippath, 1365 | "help|h" => \$help, 1366 | ) or die($usage); 1367 | if($help) { 1368 | print $usage; 1369 | exit 0; 1370 | } 1371 | Perl::Dist::APPerl::Build($zippath); 1372 | } 1373 | elsif($command eq 'configure') { 1374 | Perl::Dist::APPerl::Configure(@_); 1375 | } 1376 | elsif($command =~ /^(\-)*(halp|help|h)$/i) { 1377 | print $generic_usage; 1378 | } 1379 | elsif($command =~ /^(\-)*(version|v)$/i) { 1380 | my $message = <<"END_USAGE"; 1381 | apperlm $VERSION 1382 | Copyright (C) 2022 Gavin Arthur Hayes 1383 | This is free software; you can redistribute it and/or modify it under 1384 | the same terms as the Perl 5 programming language system itself. 1385 | END_USAGE 1386 | print $message; 1387 | } 1388 | elsif($command eq 'checkout') { 1389 | scalar(@_) == 1 or die('bad args'); 1390 | my $cfgname = $_[0]; 1391 | Perl::Dist::APPerl::Checkout($cfgname); 1392 | } 1393 | elsif($command eq 'init') { 1394 | my $usage = <<'END_USAGE'; 1395 | apperlm init [-h|--help] [-n|--name ] [-b|--base ] 1396 | -n|--name name of the default config 1397 | -b|--base base class of the config 1398 | -h|--help Show this message 1399 | Create an APPerl project, create a config if -n specified and it 1400 | doesn't already exist, checkout the config. 1401 | END_USAGE 1402 | my $name; 1403 | my $base; 1404 | my $help; 1405 | GetOptionsFromArray(\@_, "name|n=s" => \$name, 1406 | "base|b=s" => \$base, 1407 | "help|h" => \$help, 1408 | ) or die($usage); 1409 | if($help) { 1410 | print $usage; 1411 | exit 0; 1412 | } 1413 | Perl::Dist::APPerl::Init($name, $base); 1414 | } 1415 | elsif($command eq 'install-build-deps') { 1416 | my $usage = <<'END_USAGE'; 1417 | apperlm install-build-deps [-h|--help] [-c|--cosmo ] [-p|--perl ] 1418 | -c|--cosmo set path to cosmopolitan repo (skips git initialization) 1419 | -p|--perl set path to perl repo (skips git initialization) 1420 | -h|--help Show this message 1421 | Install build dependencies for APPerl, use -c or -p to skip initializing 1422 | those repos by providing a path to it. 1423 | END_USAGE 1424 | my $cosmo; 1425 | my $perl; 1426 | my $help; 1427 | GetOptionsFromArray(\@_, "cosmo|c=s" => \$cosmo, 1428 | "perl|p=s" => \$perl, 1429 | "help|h" => \$help, 1430 | ) or die($usage); 1431 | if($help) { 1432 | print $usage; 1433 | exit 0; 1434 | } 1435 | Perl::Dist::APPerl::InstallBuildDeps($perl, $cosmo); 1436 | } 1437 | elsif($command eq 'new-config') { 1438 | my $usage = <<'END_USAGE'; 1439 | apperlm new-config [-h|--help] [-n|--name ] [-b|--base ] 1440 | -n|--name name of the default config 1441 | -b|--base base class of the config 1442 | -h|--help Show this message 1443 | Create a new APPerl config and add it to the project 1444 | END_USAGE 1445 | my $name; 1446 | my $base; 1447 | my $help; 1448 | GetOptionsFromArray(\@_, "name|n=s" => \$name, 1449 | "base|b=s" => \$base, 1450 | "help|h" => \$help, 1451 | ) or die($usage); 1452 | if($help) { 1453 | print $usage; 1454 | exit 0; 1455 | } 1456 | Perl::Dist::APPerl::NewConfig($name, $base); 1457 | } 1458 | elsif($command eq 'get-config-key') { 1459 | scalar(@_) == 2 or die('bad args'); 1460 | my $itemconfig = _load_apperl_config(_load_apperl_configs()->{apperl_configs}, $_[0]); 1461 | print $itemconfig->{$_[1]}; 1462 | } 1463 | else { 1464 | die($generic_usage); 1465 | } 1466 | 1; 1467 | } 1468 | 1469 | sub _command_or_die { 1470 | print join(' ', @_), "\n"; 1471 | (system { $_[0] } @_) == 0 or die; 1472 | } 1473 | 1474 | sub _cmdoutput_or_die { 1475 | print join(' ', @_), "\n"; 1476 | my $kid = open(my $from_kid, '-|', @_) or die "can't fork $!"; 1477 | my $output = do { local $/; <$from_kid> }; 1478 | waitpid($kid, 0); 1479 | (($? >> 8) == 0) or die("child failed"); 1480 | return $output; 1481 | } 1482 | 1483 | sub _cmdinputfile_or_die { 1484 | my $input_file = pop @_; 1485 | print join(' ', @_), " < $input_file\n"; 1486 | $SIG{PIPE} = "IGNORE"; 1487 | open(my $to_kid, '|-', @_) or die "Can't fork: $!"; 1488 | copy($input_file, $to_kid) or die "failed to copy $!"; 1489 | close($to_kid); 1490 | (($? >> 8) == 0) or die "child failed $?"; 1491 | } 1492 | 1493 | sub _setup_repo { 1494 | my ($repopath, $remotes) = @_; 1495 | print "mkdir -p $repopath\n"; 1496 | make_path($repopath); 1497 | print "cd $repopath\n"; 1498 | chdir($repopath) or die "Failed to chdir $repopath"; 1499 | _command_or_die('git', 'init'); 1500 | _command_or_die('git', 'checkout', '-b', 'placeholder_dont_use'); 1501 | foreach my $remote (keys %{$remotes}) { 1502 | _command_or_die('git', 'remote', 'add', $remote, $remotes->{$remote}); 1503 | _command_or_die('git', 'fetch', $remote); 1504 | } 1505 | } 1506 | 1507 | sub _write_json { 1508 | my ($destpath, $obj) = @_; 1509 | open(my $fh, '>', $destpath) or die("Failed to open $destpath for writing"); 1510 | print $fh JSON::PP->new->pretty->encode($obj); 1511 | close($fh); 1512 | } 1513 | 1514 | sub _load_json { 1515 | my ($jsonpath) = @_; 1516 | open(my $fh, '<', $jsonpath) or return undef; 1517 | my $file_content = do { local $/; <$fh> }; 1518 | close($fh); 1519 | return decode_json($file_content); 1520 | } 1521 | 1522 | sub _load_apperl_config { 1523 | my ($apperlconfigs, $cfgname) = @_; 1524 | exists $apperlconfigs->{$cfgname} or die "Unknown config: $cfgname"; 1525 | 1526 | # find the base classes 1527 | my $item = $apperlconfigs->{$cfgname}; 1528 | my @configlist = ($item); 1529 | while(exists $item->{base}) { 1530 | $item = $apperlconfigs->{$item->{base}}; 1531 | push @configlist, $item; 1532 | } 1533 | @configlist = reverse @configlist; 1534 | 1535 | # build the config from oldest to newest 1536 | # keys that start with '+' are appended to the non-plus variant instead of replacing 1537 | # keys that start with '-' are removed from the non-plus variant instead of replacing 1538 | # Removing a key added the same stage or vice versa is undefined 1539 | my %itemconfig; 1540 | foreach my $config (@configlist) { 1541 | foreach my $key (keys %$config) { 1542 | if($key =~ /^(\+|\-)(.+)/) { 1543 | my $append = $1 eq '+'; 1544 | my $realkey = $2; 1545 | exists $itemconfig{$realkey} or die "cannot append without existing key: $realkey"; 1546 | my $rtype = ref($itemconfig{$realkey}); 1547 | $rtype or die("not ref"); 1548 | if($append) { 1549 | if($rtype eq 'ARRAY') { 1550 | $itemconfig{$realkey} = [@{$itemconfig{$realkey}}, @{$config->{$key}}]; 1551 | } 1552 | elsif($rtype eq 'HASH') { 1553 | foreach my $dest (keys %{$config->{$key}}) { 1554 | push @{$itemconfig{$realkey}{$dest}}, @{$config->{$key}{$dest}}; 1555 | } 1556 | } 1557 | else { 1558 | die($rtype); 1559 | } 1560 | } 1561 | else { 1562 | if($rtype eq 'ARRAY') { 1563 | _remove_arr_items_from_arr($itemconfig{$realkey}, $config->{$key}); 1564 | } 1565 | else { 1566 | die($rtype); 1567 | } 1568 | } 1569 | } 1570 | else { 1571 | $itemconfig{$key} = $config->{$key}; 1572 | } 1573 | } 1574 | } 1575 | 1576 | # switch these from relative paths to abs paths 1577 | foreach my $destdir (keys %{$itemconfig{zip_extra_files}}) { 1578 | foreach my $path (@{$itemconfig{zip_extra_files}{$destdir}}) { 1579 | $path = abs_path($path); 1580 | $path or die "zip_extra_files: check that all files exist for destdir: $destdir"; 1581 | -e $path or die "zip_extra_files: missing file $path"; 1582 | } 1583 | } 1584 | 1585 | # add in ourselves for bootstrapping, this even works when running internal Perl::Dist::APPerl from a bootstrapped build 1586 | if(exists $itemconfig{'include_Perl-Dist-APPerl'} && $itemconfig{'include_Perl-Dist-APPerl'}) { 1587 | my $thispath = abs_path(__FILE__); 1588 | defined($thispath) or die(__FILE__.'issues?'); 1589 | push @{$itemconfig{zip_extra_files}{"__perllib__/Perl/Dist"}}, $thispath; 1590 | my $apperlm = $0; 1591 | if(basename($0) ne 'apperlm') { 1592 | $apperlm = dirname($thispath)."/../../../script/apperlm"; 1593 | } 1594 | $apperlm = abs_path($apperlm); 1595 | defined($apperlm) or die "error getting path to apperlm"; 1596 | my @additionalfiles = ($apperlm); 1597 | -e $_ or die("$_ $!") foreach @additionalfiles; 1598 | push @{$itemconfig{zip_extra_files}{bin}}, @additionalfiles; 1599 | opendir(my $dh, SHARE_DIR) or die "error opening patch dir"; 1600 | while(my $file = readdir $dh) { 1601 | next if(($file eq '.') || ($file eq '..')); 1602 | push @{$itemconfig{zip_extra_files}{"__perllib__/auto/share/dist/Perl-Dist-APPerl"}}, SHARE_DIR."/$file"; 1603 | } 1604 | } 1605 | 1606 | # verify apperl config sanity 1607 | if(! exists $itemconfig{nobuild_perl_bin}) { 1608 | $itemconfig{cosmo_ape_loader} //= 'ape-no-modify-self.o'; 1609 | ($itemconfig{cosmo_ape_loader} eq 'ape-no-modify-self.o') || ($itemconfig{cosmo_ape_loader} eq 'ape.o') or die "Unknown ape loader: " . $itemconfig{cosmo_ape_loader}; 1610 | } 1611 | 1612 | return \%itemconfig; 1613 | } 1614 | 1615 | sub _load_user_project_config { 1616 | return _load_json(PROJECT_TMP_CONFIG_FILE); 1617 | } 1618 | 1619 | sub _load_valid_user_project_config { 1620 | my ($Configs) = @_; 1621 | my $UserProjectConfig = _load_user_project_config(); 1622 | if($UserProjectConfig) { 1623 | if(exists $UserProjectConfig->{current_apperl}) { 1624 | my $CurAPPerlName = $UserProjectConfig->{current_apperl}; 1625 | exists $Configs->{apperl_configs}{$CurAPPerlName} or die("non-existent apperl config $CurAPPerlName in user project config"); 1626 | my $itemconfig = _load_apperl_config($Configs->{apperl_configs}, $CurAPPerlName); 1627 | return ($UserProjectConfig, $CurAPPerlName, $itemconfig); 1628 | } 1629 | } 1630 | return (); 1631 | } 1632 | 1633 | sub _load_valid_configs { 1634 | my $apperlconfigs = _load_apperl_configs(); 1635 | my @configs = _load_valid_user_project_config($apperlconfigs); 1636 | return @configs if(@configs); 1637 | return () if(!exists $apperlconfigs->{defaultconfig}); 1638 | Checkout($apperlconfigs->{defaultconfig}); 1639 | return _load_valid_user_project_config($apperlconfigs); 1640 | } 1641 | 1642 | sub _load_valid_site_config { 1643 | my ($is_cosmo3) = @_; 1644 | my $SiteConfig = _load_json(SITE_CONFIG_FILE); 1645 | if ($is_cosmo3) { 1646 | $SiteConfig //= {}; 1647 | if (! exists $SiteConfig->{cosmocc}) { 1648 | print "cosmocc not found in " . SITE_CONFIG_FILE . " attempting to install cosmocc\n"; 1649 | _install_cosmocc($SiteConfig); 1650 | } 1651 | -d $SiteConfig->{cosmocc} or die $SiteConfig->{cosmocc} . ' is not a directory, please edit or remove the entry in ' . SITE_CONFIG_FILE; 1652 | } else { 1653 | $SiteConfig or die "Failed to load SiteConfig, run apperlm install-build-deps"; 1654 | -d $SiteConfig->{cosmo_repo} or die $SiteConfig->{cosmo_repo} ." is not directory, reconfigure with `apperlm install-build-deps`. Note to redownload if its already there edit ".SITE_CONFIG_FILE; 1655 | } 1656 | return $SiteConfig; 1657 | } 1658 | 1659 | sub _write_user_project_config { 1660 | my ($config) = @_; 1661 | if(! -d PROJECT_TMP_DIR) { 1662 | make_path(PROJECT_TMP_DIR); 1663 | }; 1664 | _write_json(PROJECT_TMP_CONFIG_FILE, $config); 1665 | } 1666 | 1667 | sub _copy_recursive { 1668 | my ($src, $dest) = @_; 1669 | if(! -d $dest) { 1670 | make_path($dest); 1671 | } 1672 | goto &_copy_recursive_inner; 1673 | } 1674 | 1675 | sub _copy_recursive_inner { 1676 | my ($src, $dest) = @_; 1677 | print "_copy_recursive $src $dest\n"; 1678 | if(-f $src) { 1679 | copy($src, $dest) or die("Failed to copy $!"); 1680 | } 1681 | elsif(-d $src) { 1682 | my $dest = "$dest/".basename($src); 1683 | if(! -d $dest) { 1684 | mkdir($dest) or die("Failed to mkdir $!"); 1685 | } 1686 | opendir(my $dh, $src) or die("Failed to opendir"); 1687 | while(my $file = readdir($dh)) { 1688 | next if(($file eq '.') || ($file eq '..')); 1689 | _copy_recursive("$src/$file", $dest); 1690 | } 1691 | closedir($dh); 1692 | } 1693 | else { 1694 | die "Unhandled file type for $src"; 1695 | } 1696 | } 1697 | 1698 | 1; 1699 | 1700 | __END__ 1701 | 1702 | =pod 1703 | 1704 | =encoding utf-8 1705 | 1706 | =head1 NAME 1707 | 1708 | Perl::Dist::APPerl - Actually Portable Perl 1709 | 1710 | =head1 DESCRIPTION 1711 | 1712 | Actually Portable Perl (APPerl) is a distribution of Perl the runs on 1713 | several x86_64 operating systems via the same binary. It builds to a 1714 | single binary with perl modules packed inside of it. 1715 | 1716 | Cross-platform, single binary, standalone Perl applications can be made 1717 | by building custom versions of APPerl, with and without compiling 1718 | Perl from scratch, so it can be used an alternative to L. 1719 | APPerl could also easily be added to development SDKs, 1720 | carried on your USB drive, or just allow you to run the exact same perl 1721 | on all your PCs multiple computers. 1722 | 1723 | This package documentation covers the apperlm tool for building APPerl, 1724 | APPerl usage, and how to create applications with APPerl. To handle the 1725 | chicken-and egg-situation of needing Perl to build APPerl, APPerl may 1726 | be bootstrapped from an existing build of APPerl. See README.md for 1727 | instructions. 1728 | 1729 | Information on the creation of APPerl can be found in this blog post: 1730 | L. 1731 | 1732 | =head1 SYNOPSIS 1733 | 1734 | apperlm list 1735 | apperlm checkout full 1736 | apperlm configure 1737 | apperlm build 1738 | ./perl.com /zip/bin/perldoc Perl::Dist::APPerl 1739 | cp perl.com perl 1740 | ./perl --assimilate 1741 | ln -s perl perldoc 1742 | ./perldoc perlcosmo 1743 | 1744 | To build small APPerl from scratch: 1745 | 1746 | apperlm checkout small 1747 | apperlm configure 1748 | apperlm build 1749 | 1750 | To start an APPerl project from an existing APPerl and build it: 1751 | 1752 | mkdir src 1753 | mv perl.com src/ 1754 | apperlm init --name your_config_name --base nobuild 1755 | apperlm build 1756 | 1757 | To start an APPerl project and build from scratch: 1758 | 1759 | apperlm init --name your_config_name --base small 1760 | apperlm configure 1761 | apperlm build 1762 | 1763 | =head1 apperlm 1764 | 1765 | The C (APPerl Manager) script is a CLI interface to configuring 1766 | and building APPerl. 1767 | 1768 | =head2 COMMAND REFERENCE 1769 | 1770 | =over 4 1771 | 1772 | =item * 1773 | 1774 | C creates an APPerl project, C. The 1775 | project default configuration may to specified with -n . If the 1776 | configuration does not exist, a new configuration will be created, and 1777 | then the base of the configuration may be specified with 1778 | -b . The default configuration is then checked out. 1779 | 1780 | =item * 1781 | 1782 | C lists the available APPerl configs. If a current config 1783 | is set it is denoted with a C<*>. Project configs are 1784 | labeled PROJECT. The exact configuration of a STABLE config may change 1785 | from release to release of Perl::Dist::APPerl, but only non-breaking 1786 | changes should occur. ROLLING configurations are always the latest 1787 | STABLE configurations, but breaking changes may occur from release to 1788 | release of Perl::Dist::APPerl. 1789 | 1790 | =item * 1791 | 1792 | C sets the current APPerl config, including cleaning 1793 | or reestablishing the build dirs. The current config name is written to 1794 | C<.apperl/user-project.json> . 1795 | 1796 | =item * 1797 | 1798 | C creates a new config and adds to to the project 1799 | config. -n specifies the name of the new config and must be provided. 1800 | -b specifies the base of the new config. Alternatively, you can modify 1801 | C directly. 1802 | 1803 | =item * 1804 | 1805 | C builds cosmopolitan for the current APPerl config 1806 | and runs Perl's C 1807 | 1808 | =item * 1809 | 1810 | C Cs perl and builds apperl. The output binary by 1811 | default is copied to C in the current directory, set dest in 1812 | C to customize output binary path and name. A 1813 | C binary is required to build, see README.md for details. The 1814 | C binary path may be explictly set by passing in 1815 | --zippath . 1816 | 1817 | =item * 1818 | 1819 | C installs APPerl build git dependencies. 1820 | This is now unnecessary unless you are doing vista builds or developing 1821 | APPerl itself. Note, vista builds are deprecated, see Changes. 1822 | Initialization of the repos can be skipped by passing the path to them 1823 | locally. The cosmopolitan repo initialization can be skipped with 1824 | -c . The perl5 repo initialization can be skipped with 1825 | -p . This install is done user specific, installs to 1826 | $XDG_CONFIG_HOME/apperl . 1827 | 1828 | =back 1829 | 1830 | =head1 USAGE 1831 | 1832 | APPerl doesn't need to be installed, the output C binary can 1833 | be copied between computers and ran without installation. However, in 1834 | certain cases such as magic (modifying $0, etc.) The binary must be 1835 | assimilated for it to work properly. Note, you likely want to copy 1836 | before this operation as it modifies the binary in-place to be bound to 1837 | the current environment. 1838 | cp perl.com perl 1839 | ./perl --assimilate 1840 | 1841 | For the most part, APPerl works like normal perl, however it has a 1842 | couple additional features. 1843 | 1844 | =head2 EMBEDDED SCRIPTS 1845 | 1846 | The APPerl binary is also a ZIP file. Paths starting with C 1847 | refer to files compressed in the binary itself. At runtime the zip 1848 | filesystem is readonly, but additional modules and scripts can be added 1849 | just by adding them to the zip file. For example, perldoc and the other 1850 | standard scripts are shipped inside of C 1851 | 1852 | ./perl.com /zip/bin/perldoc perlcosmo 1853 | 1854 | For convenience, APPerl has some other ways of invoking embedded 1855 | scripts: 1856 | 1857 | =over 4 1858 | 1859 | =item * 1860 | 1861 | C - When the environment variable C 1862 | is set, APPerl attempts to load the basename of C 1863 | without file extension from C or opens the perl interpreter 1864 | like normal if it is C. 1865 | 1866 | APPERL_SCRIPTNAME=perldoc ./perl.com perlcosmo 1867 | 1868 | =item * 1869 | 1870 | C - If C is not set, APPerl attempts to 1871 | load the basename of C without file extension from C 1872 | or opens the perl interpreter like normal if it is C. This 1873 | enables making single binary perl applications, with a symlink, move, 1874 | or copy! 1875 | 1876 | ln -s perl.com perldoc.com 1877 | ./perldoc.com perlcosmo 1878 | 1879 | =item * 1880 | 1881 | C - If C doesn't yield a valid target 1882 | either, if the C field inside of the binary 1883 | is set, APPerl will attempt to load that. This way is meant for APPerl 1884 | application authors to protect against accidental rename messing up 1885 | C script execution. L 1886 | shows how to set it with C<"default_script">, but you could also 1887 | set/change it, by searching for C in a hex 1888 | editor and modifying it. 1889 | 1890 | =back 1891 | 1892 | If a valid target is not found via the script execution methods, the 1893 | perl interpreter is invoked like normal. 1894 | 1895 | =head1 CREATING APPLICATIONS WITH APPERL 1896 | 1897 | =head2 RATONALE 1898 | 1899 | APPerl wasn't developed to be the 'hack of the day', but provide real 1900 | world utility by easing using Perl in user environments. 1901 | 1902 | Unfortunately, scripting languages are often a second class citizen on 1903 | user environments due to them not being installed by default or only 1904 | broken/old/incomplete versions installed, and sometimes not being the 1905 | easiest to install. Providing native perl binaries with solutions like 1906 | L is possible, but that requires juggling binaries for 1907 | every desired target and packing. 1908 | 1909 | The idea of APPerl applications is that you can handcraft the desired 1910 | Perl environment with your application and then ship it as one portable 1911 | binary for all targets. 1912 | 1913 | Building an APPerl application does nothing to ofuscate or hide your 1914 | source code, it is a feature that APPerl binaries are also zip files, 1915 | allowing for easy retrieval of Perl scripts and modules. 1916 | 1917 | =head2 BUILDING AN APPLICATION FROM EXISTING APPERL 1918 | 1919 | The easiest way to build an APPerl application is to build it from 1920 | existing APPerl. If your application doesn't depend on non-standard 1921 | C or XS extensions, it can be built from one of the official APPerl 1922 | builds, skipping the need for building Perl from scratch. 1923 | 1924 | Enter your projects directory, create it if it doesn't exists. Download 1925 | or copy in an existing version of APPerl you wish to build off of. 1926 | Official builds are available on the APPerl web page: 1927 | L. 1928 | Create a new nobuild APPerl project and build it. 1929 | 1930 | cd projectdir 1931 | mkdir src 1932 | cp ./perl.com src/ 1933 | apperlm init --name my_nobuild_config 1934 | apperlm build 1935 | 1936 | Now you should have a newly built perl.com inside the current 1937 | directory. However, this isn't very exciting as it's identical to the 1938 | one you copied into src. Let's create a script. 1939 | 1940 | printf "%s\n" \ 1941 | '#!/usr/bin/perl' \ 1942 | 'use strict; use warnings;' \ 1943 | 'print "Hello, World!\n";' > src/hello 1944 | 1945 | To add it open apperl-project.json and add the following to 1946 | my_nobuild_config: 1947 | 1948 | "zip_extra_files" : { "bin" : ["src/hello"] } 1949 | 1950 | Rebuild and try loading the newly added script 1951 | 1952 | apperlm build 1953 | ./perl.com /zip/bin/hello 1954 | 1955 | You have embedded a script inside APPerl, however running it is a 1956 | little awkward. What if you could run it by the name of the script? 1957 | APPerl has argv[0] script execution, enabling the following: 1958 | 1959 | ln -s perl.com hello 1960 | ./hello 1961 | 1962 | Now, you may still wish for your application to be run, even if the 1963 | executable is renamed. Add C to your config to set a 1964 | fallback script: 1965 | 1966 | "default_script" : "/zip/bin/hello" 1967 | 1968 | Now, what about Perl modules? Perl modules can be packed in the same 1969 | way, but to ease setting the correct directory to packing them into, 1970 | the magic prefix __perllib__ can be used in the destination. Note, you 1971 | may have to add items to the MANIFEST key if the MANIFEST isn't set 1972 | permissively already. 1973 | 1974 | "zip_extra_files" : { "__perllib__/Your" : ["Module.pm"] } 1975 | 1976 | =head2 BUILDING AN APPLICATION FROM SCRATCH 1977 | 1978 | If your application requires non-standard C or XS extensions, or you 1979 | would like to install CPAN distributions through their standard 1980 | mechanisms (C or C), APPerl must be built from 1981 | scratch as it only supports static linking and installing distributions 1982 | may require adding in extensions. Note, this process can only be 1983 | completed on Linux as building the Cosmopolitan Libc from scratch is 1984 | only supported on Linux and APPerl uses the unix-like C to 1985 | configure perl. This tutorial assumes you already have an APPerl 1986 | project, possibly from following the L 1987 | tutorial. 1988 | 1989 | First install the APPerl build dependencies and create a new config 1990 | based on the current full config, checkout, configure, and build. 1991 | 1992 | apperlm install-build-deps 1993 | apperlm new-config --name my_src_build_config --base full 1994 | apperlm checkout my_src_build_config 1995 | apperlm configure 1996 | apperlm build 1997 | 1998 | If all goes well you should have compiled APPerl from source! 1999 | 2000 | ./perl.com -V 2001 | stat perl.com 2002 | 2003 | =head3 ADDING CPAN DISTRIBUTIONS 2004 | 2005 | The recommended way of adding CPAN distributions or C or XS extensions 2006 | is via the C<"install_modules"> mechanism. 2007 | 2008 | Currently, no CPAN client is used, so you must download or make 2009 | available or disk otherwise the needed distributions for C 2010 | to be able to build and install them into your APPerl. It supports 2011 | folder paths and paths to tarballs such as the one's directly 2012 | downloaded from CPAN. 2013 | 2014 | For example to install B, download its tarball from CPAN 2015 | and add to to my_src_build_config in apperl-project.json: 2016 | 2017 | "install_modules" : ["Geo-Calc-XS-0.33.tar.gz"] 2018 | 2019 | Then, build and test it: 2020 | 2021 | apperlm build 2022 | ./perl.com -MGeo::Calc::XS -e 'print $Geo::Calc::XS::VERSION' 2023 | 2024 | Distributions in C<"install_modules"> are installed in order, so 2025 | modules with dependencies just need them to be installed before in 2026 | order for them to be added. 2027 | 2028 | =cut 2029 | 2030 | =head3 ADDING VIA PERL BUILD 2031 | 2032 | This method is B as many modules/extensions cannot be 2033 | built this way, it only works for modules that can be built with 2034 | C, do not have dependencies, and requires reconfiguring Perl. 2035 | The method listed in L supersedes this 2036 | method. 2037 | 2038 | Now let's create a very basic C extension. 2039 | 2040 | mkdir MyCExtension 2041 | printf "%s\n" \ 2042 | "package MyCExtension;" \ 2043 | "use strict; use warnings;" \ 2044 | "our \$VERSION = '0.0';" \ 2045 | "require XSLoader;" \ 2046 | 'XSLoader::load("MyCExtension", $VERSION);' \ 2047 | "1;" > MyCExtension/MyCExtension.pm 2048 | printf "%s\n" \ 2049 | '#define PERL_NO_GET_CONTEXT' \ 2050 | '#include "EXTERN.h"' \ 2051 | '#include "perl.h"' \ 2052 | '#include "XSUB.h"' \ 2053 | '#include ' \ 2054 | '' \ 2055 | 'MODULE = MyCExtension PACKAGE = MyCExtension' \ 2056 | '' \ 2057 | 'void' \ 2058 | 'helloworld()' \ 2059 | ' CODE:' \ 2060 | ' printf("Hello, World!\n");' > MyCExtension/MyCExtension.xs 2061 | 2062 | Add it to my_src_build_config in apperl-project.json . Keys that begin 2063 | with '+' will be merged with the non-plus variant of the parent config. 2064 | Keys the begin with '-' will be removed from the non-minus variant of 2065 | the parent config. 2066 | 2067 | "perl_repo_files" : { "ext" : [ 2068 | "MyCExtension" 2069 | ]}, 2070 | "+MANIFEST" : ["__perlarchlib__/MyCExtension.pm"], 2071 | "+perl_onlyextensions" : ["MyCExtension"] 2072 | 2073 | Build it and try it out. apperlm checkout is needed as Perl must be 2074 | rebuilt from scratch as the Configure flags changed and new files were 2075 | added to the perl5 build dir. 2076 | 2077 | apperlm checkout my_src_build_config 2078 | apperlm configure 2079 | apperlm build 2080 | ./perl-small.com -MMyCExtension -e 'MyCExtension::helloworld();' 2081 | 2082 | Now for completeness sake, let's turn this custom build of APPerl into 2083 | an application that calls the extension function we just added. First 2084 | make the application main script. 2085 | 2086 | printf "%s\n" \ 2087 | '#!/usr/bin/perl' \ 2088 | 'use strict; use warnings;' \ 2089 | 'use MyCExtension;' \ 2090 | 'MyCExtension::helloworld();' > helloext 2091 | 2092 | Then, add it the project config and set the dest binary name to match 2093 | the script so that it will launch the script. 2094 | 2095 | "dest" : "helloext.com", 2096 | "+MANIFEST" : ["__perlarchlib__/MyCExtension.pm", "bin/helloext"], 2097 | "zip_extra_files" : { "bin" : ["helloext"] } 2098 | 2099 | Build and test it. 2100 | 2101 | apperlm build 2102 | ./helloext.com 2103 | 2104 | =head1 DEBUGGING 2105 | 2106 | APPerl binaries as with other Actually Portable Executables built with 2107 | the Cosmopolitan Libc have some nice debug features: 2108 | 2109 | Syscall logging can be performed just by running with C<--strace> as 2110 | the first argument: 2111 | 2112 | ./perl.com --strace /zip/bin/perldoc perlcosmo 2113 | 2114 | Function call logging can be performed if you have the accompanying 2115 | C<.com.dbg> file in the same directory as your APPerl binary: 2116 | 2117 | ./perl.com --ftrace /zip/bin/perldoc perlcosmo 2118 | 2119 | In theory, it should be possible to use C with APPerl binaries, 2120 | but the author has had great difficulty getting this to work. The 2121 | C APPerl config is available to build Cosmopolitan with C 2122 | and Perl with C<-Doptimize=-g3 -gdwarf-4>. 2123 | 2124 | =head1 SUPPORT AND DOCUMENTATION 2125 | 2126 | APPerl web page: L 2127 | 2128 | Support and bug reports can be found at the repository 2129 | L 2130 | 2131 | =head1 ACKNOWLEDGEMENTS 2132 | 2133 | The Cosmopolitan Libc (L) 2134 | contributors, especially Justine Tunney (L) and 2135 | Gautham Venkatasubramanian (L). APPerl 2136 | wouldn't be possible without Actually Portable Executables and 2137 | polyfills of several Linux and POSIX APIs for other platforms. 2138 | Gautham's Python port 2139 | (L) 2140 | inspired this project. 2141 | 2142 | =head1 AUTHOR 2143 | 2144 | Gavin Hayes, C<< >> 2145 | 2146 | =head1 LICENSE AND COPYRIGHT 2147 | 2148 | This software is copyright (c) 2024 by Gavin Hayes. 2149 | 2150 | This is free software; you can redistribute it and/or modify it under 2151 | the same terms as the Perl 5 programming language system itself. 2152 | 2153 | =cut -------------------------------------------------------------------------------- /script/apperlm: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; use warnings; 3 | use Perl::Dist::APPerl; 4 | Perl::Dist::APPerl::apperlm(@ARGV); 5 | -------------------------------------------------------------------------------- /share/5.36-cosmo-apperl.patch: -------------------------------------------------------------------------------- 1 | diff --git a/patchlevel.h b/patchlevel.h 2 | index d52e867594..24b01754d5 100644 3 | --- a/patchlevel.h 4 | +++ b/patchlevel.h 5 | @@ -158,7 +158,9 @@ hunk. 6 | static const char * const local_patches[] = { 7 | NULL 8 | ,"G4Vi:cosmo/c473e9-73ecc6c - https://github.com/G4Vi/perl5/compare/c473e9~1...73ecc6c various changes to support building with the Cosmopolitan Libc" 9 | + ,"G4Vi:cosmo-apperl/9719db2 - https://github.com/G4Vi/perl5/commit/9719db2dfbb19454177a31d8ce874a61f17a30da add argv[0] /zip/bin script launching" 10 | ,"G4Vi:cosmo/2fb034f - https://github.com/G4Vi/perl5/commit/2fb034ffb02db2b3ac09706c954704930c620c0b fix Time-HiRes Configure to work for cosmopolitan" 11 | + ,"G4Vi:cosmo-apperl/9fdd50f-7628a53 - https://github.com/G4Vi/perl5/compare/9fdd50f~1...7628a53 Add APPERL_DEFAULT_SCRIPT and APPERL_SCRIPTNAME script launching" 12 | ,"G4Vi:cosmo/3643b8b - https://github.com/G4Vi/perl5/commit/3643b8bd369ea1e8715a27ce8821c8e70f2c17e0 add cosmo as Unix in Perl::OSType (fixes Module::Build)" 13 | ,"G4Vi:cosmo/e3d8537 - https://github.com/G4Vi/perl5/commit/e3d853703f5c7c951a14e1eed186105cc0e0b7e3 s/perl.elf$/perl.com.dbg/ as perl.com.dbg is useful for --ftrace" 14 | ,"G4Vi:cosmo/7138814 - https://github.com/G4Vi/perl5/commit/713881482f9968f4960090d2699bc4cb4a46dc94 update for cosmo 3.0.2, new ape copying" 15 | diff --git a/perl.c b/perl.c 16 | index 79946460e5..fce1c67c47 100644 17 | --- a/perl.c 18 | +++ b/perl.c 19 | @@ -2075,6 +2075,52 @@ S_parse_body(pTHX_ char **env, XSINIT_t xsinit) 20 | 21 | init_main_stash(); 22 | 23 | + // check for APPERL_SCRIPTNAME or argv[0] or default script execution 24 | + do { 25 | + const char *envscriptname = getenv("APPERL_SCRIPTNAME"); 26 | + const char *programname = envscriptname ? envscriptname : argv[0]; 27 | + const char *slash = strrchr(programname, '/'); 28 | + if(slash != NULL) 29 | + { 30 | + programname = slash + 1; 31 | + } 32 | + const char *dot = strrchr(programname, '.'); 33 | + const unsigned namelen = dot ? dot - programname : strlen(programname); 34 | + 35 | + // shortcut for normal execution 36 | + if((namelen == 4) && (memcmp("perl", programname, 4) == 0)) 37 | + { 38 | + break; 39 | + } 40 | + 41 | + // /zip/bin/ script execution 42 | + #define SCRIPTPATH "/zip/bin/" 43 | + static char name[256] = SCRIPTPATH; 44 | + if(sizeof(SCRIPTPATH)+namelen <= sizeof(name)) 45 | + { 46 | + memcpy(name + sizeof(SCRIPTPATH) - 1, programname, namelen); 47 | + name[sizeof(SCRIPTPATH)-1+namelen] = '\0'; 48 | + struct stat st; 49 | + if((stat(name, &st) == 0) && S_ISREG(st.st_mode)) 50 | + { 51 | + scriptname = name; 52 | + break; 53 | + } 54 | + } 55 | + #undef SCRIPTPATH 56 | + 57 | + // default script 58 | + #define DEFAULT_SCRIPT_SENTINEL "APPERL_DEFAULT_SCRIPT" 59 | + volatile static const char default_script[sizeof(DEFAULT_SCRIPT_SENTINEL)+256] = DEFAULT_SCRIPT_SENTINEL; 60 | + if(default_script[sizeof(DEFAULT_SCRIPT_SENTINEL)]) 61 | + { 62 | + scriptname = &default_script[sizeof(DEFAULT_SCRIPT_SENTINEL)]; 63 | + break; 64 | + } 65 | + #undef DEFAULT_SCRIPT_SENTINEL 66 | + } while(0); 67 | + 68 | + if(scriptname == NULL) 69 | { 70 | const char *s; 71 | for (argc--,argv++; argc > 0; argc--,argv++) { 72 | -------------------------------------------------------------------------------- /share/5.36-cosmo.patch: -------------------------------------------------------------------------------- 1 | diff --git a/.mailmap b/.mailmap 2 | index 72a8a4d6a7..37c3ffce5f 100644 3 | --- a/.mailmap 4 | +++ b/.mailmap 5 | @@ -646,6 +646,7 @@ Gabor Szabo Gabor Szabo 6 | Garry T. Williams Garry T. Williams 7 | Gary Clark Gary Clark 8 | Gary L. Armstrong Gary L. Armstrong 9 | +Gavin Hayes Gavin Hayes 10 | Gavin Shelley Gavin Shelley 11 | Gene Sullivan gene sullivan 12 | Gene Sullivan Gene Sullivan 13 | diff --git a/AUTHORS b/AUTHORS 14 | index 8f25e9d835..8fcde9e4e2 100644 15 | --- a/AUTHORS 16 | +++ b/AUTHORS 17 | @@ -482,6 +482,7 @@ Garry T. Williams 18 | Gary Clark 19 | Gary L. Armstrong 20 | Gary Ng <71564.1743@compuserve.com> 21 | +Gavin Hayes 22 | Gavin Shelley 23 | Gene Sullivan 24 | Geoffrey F. Green 25 | diff --git a/Configure b/Configure 26 | index 67e990217d..e56aa7d0a6 100755 27 | --- a/Configure 28 | +++ b/Configure 29 | @@ -2744,7 +2744,7 @@ int main(int argc, char *argv[]) { 30 | return 0; 31 | } 32 | EOM 33 | - if $cc -o try $ccflags $ldflags try.c; then 34 | + if $cc -o try $ccflags $ldflags try.c $libs; then 35 | : 36 | else 37 | echo "Uh-oh, the C compiler '$cc' doesn't seem to be working." >&4 38 | @@ -2816,7 +2816,7 @@ int main(int argc, char *argv[]) { 39 | return 0; 40 | } 41 | EOM 42 | - if $cc -o try $ccflags $ldflags try.c; then 43 | + if $cc -o try $ccflags $ldflags try.c $libs; then 44 | : 45 | else 46 | if $test X"$despair" = Xyes; then 47 | @@ -3665,6 +3665,11 @@ EOM 48 | fi 49 | fi 50 | 51 | + if [ $COSMO_REPO ]; then 52 | + osname='cosmo' 53 | + osvers='' 54 | + fi 55 | + 56 | case "$targetarch" in 57 | '') ;; 58 | *) hostarch=$osname 59 | @@ -4576,7 +4581,7 @@ int main() { 60 | return(0); 61 | } 62 | EOM 63 | -if $cc -o try $ccflags $ldflags try.c; then 64 | +if $cc -o try $ccflags $ldflags try.c $libs; then 65 | gccversion=`$run ./try` 66 | case "$gccversion" in 67 | '') echo "You are not using GNU cc." ;; 68 | @@ -4697,7 +4702,7 @@ int main(int argc, char **argv) { 69 | EOCP 70 | c99_for=no 71 | for flag in '' '-std=gnu99' '-std=c99'; do 72 | - if $cc -o try $flag $ccflags $ldflags try.c 2>/dev/null && ./try; then 73 | + if $cc -o try $flag $ccflags $ldflags try.c $libs 2>/dev/null && ./try; then 74 | c99_for="$flag" 75 | break; 76 | fi 77 | @@ -5401,7 +5406,7 @@ echo " "; 78 | echo "Checking if your compiler accepts $flag" >&4; 79 | [ "X$sysroot" != "X" ] && echo "For sysroot = $sysroot"; 80 | echo "int main(void) { return 0; }" > gcctest.c; 81 | -if $cc $_sysroot -O2 $flag -o gcctest gcctest.c 2>gcctest.out && $run ./gcctest; then 82 | +if $cc $_sysroot -O2 $flag -o gcctest $ccflags $ldflags gcctest.c $libs 2>gcctest.out && $run ./gcctest; then 83 | echo "Yes, it does." >&4; 84 | if $test -s gcctest.out ; then 85 | echo "But your platform does not like it:"; 86 | diff --git a/MANIFEST b/MANIFEST 87 | index c2057ee452..8e9795c82d 100644 88 | --- a/MANIFEST 89 | +++ b/MANIFEST 90 | @@ -4303,6 +4303,9 @@ ext/Errno/ChangeLog Errno changes 91 | ext/Errno/Errno_pm.PL Errno perl module create script 92 | ext/Errno/Makefile.PL Errno extension makefile writer 93 | ext/Errno/t/Errno.t See if Errno works 94 | +ext/ErrnoRuntime/ErrnoRuntime.xs ErrnoRuntime extension implementation 95 | +ext/ErrnoRuntime/lib/ErrnoRuntime.pm ErrnoRuntime extension Perl module 96 | +ext/ErrnoRuntime/Makefile.PL ErrnoRuntime extension makefile writer 97 | ext/ExtUtils-Miniperl/lib/ExtUtils/Miniperl.pm Writes {mini,}perlmain.c 98 | ext/Fcntl/Fcntl.pm Fcntl extension Perl module 99 | ext/Fcntl/Fcntl.xs Fcntl extension external subroutines 100 | @@ -4765,6 +4768,7 @@ hints/broken-db.msg Warning message for systems with broken DB library 101 | hints/bsdos.sh Hints for named architecture 102 | hints/catamount.sh Hints for named architecture 103 | hints/convexos.sh Hints for named architecture 104 | +hints/cosmo.sh Hints for named architecture 105 | hints/cxux.sh Hints for named architecture 106 | hints/cygwin.sh Hints for named architecture 107 | hints/darwin.sh Hints for named architecture 108 | @@ -5517,6 +5521,7 @@ README.amiga Perl notes for AmigaOS 109 | README.android Perl notes for Android 110 | README.bs2000 Perl notes for POSIX-BC BS2000 111 | README.cn Perl for Simplified Chinese (in UTF-8) 112 | +README.cosmo Perl notes for the Cosmopolitan Libc 113 | README.cygwin Perl notes for Cygwin 114 | README.freebsd Perl notes for FreeBSD 115 | README.haiku Perl notes for Haiku 116 | diff --git a/Makefile.SH b/Makefile.SH 117 | index cb0efb32ab..a5ca34741f 100755 118 | --- a/Makefile.SH 119 | +++ b/Makefile.SH 120 | @@ -1001,6 +1001,20 @@ lib/buildcustomize.pl: $& $(miniperl_objs) write_buildcustomize.pl 121 | $(MINIPERL) -f write_buildcustomize.pl 122 | !NO!SUBS! 123 | ;; 124 | + cosmo*) 125 | + $spitshell >>$Makefile <<'!NO!SUBS!' 126 | +lib/buildcustomize.pl: $& $(miniperl_dep) write_buildcustomize.pl 127 | + -@rm -f miniperl.xok 128 | + $(CC) $(CLDFLAGS) -o miniperl.com.dbg \ 129 | + $(miniperl_objs) $(libs) 130 | + $(realpath $(dir $(CC)))/x86_64-linux-musl-objcopy -S -O binary miniperl.com.dbg miniperl.com 131 | + cp miniperl.com $(MINIPERL_EXE) 132 | + chmod -w miniperl.com 133 | + ./miniperl --assimilate || true 134 | + $(LDLIBPTH) ./miniperl$(HOST_EXE_EXT) -w -Ilib -Idist/Exporter/lib -MExporter -e '' || sh -c 'echo >&2 Failed to build miniperl. Please run make minitest; exit 1' 135 | + $(MINIPERL) -f write_buildcustomize.pl 136 | +!NO!SUBS! 137 | + ;; 138 | *) 139 | if test "X$hostperl" != X; then 140 | $spitshell >>$Makefile <>$Makefile <<'!NO!SUBS!' 147 | + $(SHRPENV) $(CC) -o perl.com.dbg $(CLDFLAGS) $(CCDLFLAGS) $(perlmain_objs) $(static_ext) $(LLIBPERL) `cat ext.libs` $(libs) 148 | + $(realpath $(dir $(CC)))/x86_64-linux-musl-objcopy -S -O binary perl.com.dbg perl.com 149 | + cp perl.com $(PERL_EXE) 150 | + chmod -w perl.com 151 | + ./perl --assimilate || true 152 | +!NO!SUBS! 153 | + ;; 154 | *) $spitshell >>$Makefile <<'!NO!SUBS!' 155 | $(SHRPENV) $(CC) -o perl $(CLDFLAGS) $(CCDLFLAGS) $(perlmain_objs) $(static_ext) $(LLIBPERL) `cat ext.libs` $(libs) 156 | !NO!SUBS! 157 | diff --git a/Porting/Maintainers.pl b/Porting/Maintainers.pl 158 | index 1413ce02fc..49200f34b7 100755 159 | --- a/Porting/Maintainers.pl 160 | +++ b/Porting/Maintainers.pl 161 | @@ -1385,6 +1385,7 @@ use File::Glob qw(:case); 162 | ext/Devel-Peek/ 163 | ext/DynaLoader/ 164 | ext/Errno/ 165 | + ext/ErrnoRuntime/ 166 | ext/ExtUtils-Miniperl/ 167 | ext/Fcntl/ 168 | ext/File-DosGlob/ 169 | diff --git a/README.cosmo b/README.cosmo 170 | new file mode 100644 171 | index 0000000000..e5b5de8952 172 | --- /dev/null 173 | +++ b/README.cosmo 174 | @@ -0,0 +1,87 @@ 175 | +If you read this file _as_is_, just ignore the funny characters you see. 176 | +It is written in the POD format (see pod/perlpod.pod) which is specially 177 | +designed to be readable as is. 178 | + 179 | +=head1 NAME 180 | + 181 | +perlcosmo - Build-once run-anywhere Perl using the Cosmopolitan Libc 182 | + 183 | +=head1 DESCRIPTION 184 | + 185 | +The cosmo platform addition eases building Perl with the Cosmopolitan 186 | +Libc. When you build with the Cosmopolitan Libc, the libc is the 187 | +platform as the Cosmopolitan Libc targets building simultaneous support 188 | +for multiple operating systems (Unixes, Windows, etc) into the same 189 | +binary. 190 | + 191 | +To get the most benefits of the cosmo platform, you likely want to 192 | +build Actually Portable Perl (APPerl) instead of this directly. See 193 | +L ; APPerl Manager (apperlm) includes a front-end 194 | +for building perl from source with the Cosmopolitan Libc. The 195 | +instructions in this document only cover building perl, not building or 196 | +packaging into APPerl (single executable perl with perl modules 197 | +embedded inside). 198 | + 199 | +=head1 BUILD 200 | + 201 | +Download the Cosmopolitan Libc and build with the desired MODE: 202 | + 203 | + git clone https://github.com/jart/cosmopolitan ../cosmopolitan 204 | + make -C ../cosmopolitan -j4 MODE= 205 | + 206 | +Run Configure, but with some environment variables to point it at 207 | +cosmopolitan; update COSMO_MODE to the MODE you set before and 208 | +COSMO_REPO to the absolute path of the cosmopolitan repo. Then, make 209 | +and install like usual. 210 | + 211 | + COSMO_MODE= COSMO_REPO="/home/gavin/cosmopolitan" ./Configure -de 212 | + make 213 | + make install 214 | + 215 | +Note the installed binary is assimilated (see Cosmopolitan Libc 216 | +--assimilate flag), meaning it only runs on the current operating 217 | +system. The perl.com in the perl repo, however, is actually portable 218 | +and will run on several operating systems. For a solution that builds 219 | +on this, by packaging perl modules and scripts inside of the executable 220 | +and more, see L. 221 | + 222 | +=head1 KNOWN PROBLEMS 223 | + 224 | +cosmo perl is a work in progress, many major issues are present. 225 | + 226 | +=over 4 227 | + 228 | +=item * 229 | + 230 | +C behavior when a shell is required, depends on the currently 231 | +running operating system. On most systems it uses, C, but on 232 | +Windows it uses C. Therefore, it's still hard to use portably. 233 | +However, it is sufficient for pulling up a pager for L . 234 | + 235 | +=item * 236 | + 237 | +After building, only Pure Perl modules may be added as perl is built 238 | +statically. 239 | + 240 | +=item * 241 | + 242 | +Some magic only works when the binary is assimilated. For example, 243 | +modifying C<$0>. Running with C<--assimilate> will bind the binary to 244 | +the current operating system. 245 | + 246 | +=back 247 | + 248 | +=head1 ACKNOWLEDGEMENTS 249 | + 250 | +The L 251 | +contributors, especially L and 252 | +L. 253 | +Gautham's 254 | +L 255 | +to the Cosmopolitan Libc inspired this port. 256 | + 257 | +=head1 CONTACT 258 | + 259 | +The port in-progress is being done by Gavin Hayes 260 | + 261 | +Last update: 2022-10-11 262 | diff --git a/cpan/ExtUtils-Constant/lib/ExtUtils/Constant/ProxySubs.pm b/cpan/ExtUtils-Constant/lib/ExtUtils/Constant/ProxySubs.pm 263 | index 0aee5233fe..cd17c1c86f 100644 264 | --- a/cpan/ExtUtils-Constant/lib/ExtUtils/Constant/ProxySubs.pm 265 | +++ b/cpan/ExtUtils-Constant/lib/ExtUtils/Constant/ProxySubs.pm 266 | @@ -406,13 +406,14 @@ EOC 267 | 268 | print $c_fh "struct $struct_type $struct;\n"; 269 | 270 | + my $structtypetype = $type ? 'static struct' : 'static const struct'; 271 | print $struct_fh <<"EOBOOT"; 272 | 273 | - static const struct $struct_type $array_name\[] = 274 | + $structtypetype $struct_type $array_name\[] = 275 | { 276 | EOBOOT 277 | 278 | - 279 | + my @valuestowrite; 280 | foreach my $item (@{$found->{$type}}) { 281 | my ($name, $namelen, $value, $macro) 282 | = $self->name_len_value_macro($item); 283 | @@ -429,8 +430,8 @@ EOBOOT 284 | } else { 285 | print $struct_fh $ifdef; 286 | } 287 | - print $struct_fh " { ", join (', ', "\"$name\"", $namelen, 288 | - &$type_to_value($value)), 289 | + push @valuestowrite, &$type_to_value($value); 290 | + print $struct_fh " { ", join (', ', "\"$name\"", $namelen), 291 | " },\n", 292 | $self->macro_to_endif($macro); 293 | } 294 | @@ -438,6 +439,28 @@ EOBOOT 295 | # Terminate the list with a NULL 296 | print $struct_fh " { NULL, 0", (", 0" x $number_of_args), " } };\n"; 297 | 298 | + if($type) { 299 | + print $struct_fh "{\nunsigned i = 0;\n"; 300 | + foreach my $item (@{$found->{$type}}) { 301 | + my ($name, $namelen, $value, $macro) = $self->name_len_value_macro($item); 302 | + my $ifdef = $self->macro_to_ifdef($macro); 303 | + if (!$ifdef && $item->{invert_macro}) { 304 | + carp("Attempting to supply a default for '$name' which has no conditional macro"); 305 | + next; 306 | + } 307 | + if ($item->{invert_macro}) { 308 | + print $struct_fh $self->macro_to_ifndef($macro); 309 | + print $struct_fh 310 | + " /* This is the default value: */\n" if $type; 311 | + } else { 312 | + print $struct_fh $ifdef; 313 | + } 314 | + print $struct_fh $array_name,"[i++].value = ". (shift @valuestowrite) . ";\n"; 315 | + print $struct_fh $self->macro_to_endif($macro); 316 | + } 317 | + print $struct_fh "}\n"; 318 | + } 319 | + 320 | print $xs_fh <<"EOBOOT" if $type; 321 | const struct $struct_type *$iterator{$type} = $array_name; 322 | EOBOOT 323 | diff --git a/cpan/Perl-OSType/lib/Perl/OSType.pm b/cpan/Perl-OSType/lib/Perl/OSType.pm 324 | index a72dd024b5..a0f2606137 100644 325 | --- a/cpan/Perl-OSType/lib/Perl/OSType.pm 326 | +++ b/cpan/Perl-OSType/lib/Perl/OSType.pm 327 | @@ -55,6 +55,7 @@ my %OSTYPES = qw( 328 | nto Unix 329 | qnx Unix 330 | android Unix 331 | + cosmo Unix 332 | 333 | dos Windows 334 | MSWin32 Windows 335 | diff --git a/cpan/Pod-Perldoc/lib/Pod/Perldoc.pm b/cpan/Pod-Perldoc/lib/Pod/Perldoc.pm 336 | index bb6ffc83ef..af5878313a 100644 337 | --- a/cpan/Pod-Perldoc/lib/Pod/Perldoc.pm 338 | +++ b/cpan/Pod-Perldoc/lib/Pod/Perldoc.pm 339 | @@ -1929,7 +1929,7 @@ sub page { # apply a pager to the output file 340 | $self->aside("About to try calling $pager $output\n"); 341 | if ($self->is_vms) { 342 | last if system("$pager $output") == 0; 343 | - } elsif($self->is_amigaos) { 344 | + } elsif($self->is_amigaos) { 345 | last if system($pager, $output) == 0; 346 | } else { 347 | last if system("$pager \"$output\"") == 0; 348 | diff --git a/cpan/Socket/Socket.xs b/cpan/Socket/Socket.xs 349 | index b4bccb796d..3ec940c3e6 100644 350 | --- a/cpan/Socket/Socket.xs 351 | +++ b/cpan/Socket/Socket.xs 352 | @@ -1165,7 +1165,7 @@ inet_ntop(af, ip_address_sv) 353 | STRLEN addrlen; 354 | #ifdef AF_INET6 355 | struct in6_addr addr; 356 | - char str[INET6_ADDRSTRLEN]; 357 | + char str[65]; 358 | #else 359 | struct in_addr addr; 360 | char str[INET_ADDRSTRLEN]; 361 | @@ -1177,20 +1177,19 @@ inet_ntop(af, ip_address_sv) 362 | 363 | ip_address = SvPVbyte(ip_address_sv, addrlen); 364 | 365 | - switch(af) { 366 | - case AF_INET: 367 | - if(addrlen != 4) 368 | + if(af == AF_INET) { 369 | + if(addrlen != 4) 370 | croak("Bad address length for Socket::inet_ntop on AF_INET;" 371 | " got %" UVuf ", should be 4", (UV)addrlen); 372 | - break; 373 | + } 374 | #ifdef AF_INET6 375 | - case AF_INET6: 376 | - if(addrlen != 16) 377 | + else if(af == AF_INET6) { 378 | + if(addrlen != 16) 379 | croak("Bad address length for Socket::inet_ntop on AF_INET6;" 380 | " got %" UVuf ", should be 16", (UV)addrlen); 381 | - break; 382 | + } 383 | #endif 384 | - default: 385 | + else { 386 | croak("Bad address family for %s, got %d, should be" 387 | #ifdef AF_INET6 388 | " either AF_INET or AF_INET6", 389 | @@ -1230,16 +1229,15 @@ inet_pton(af, host) 390 | struct in_addr ip_address; 391 | #endif 392 | 393 | - switch(af) { 394 | - case AF_INET: 395 | - addrlen = 4; 396 | - break; 397 | + if(af == AF_INET) { 398 | + addrlen = 4; 399 | + } 400 | #ifdef AF_INET6 401 | - case AF_INET6: 402 | - addrlen = 16; 403 | - break; 404 | + else if(af == AF_INET6) { 405 | + addrlen = 16; 406 | + } 407 | #endif 408 | - default: 409 | + else { 410 | croak("Bad address family for %s, got %d, should be" 411 | #ifdef AF_INET6 412 | " either AF_INET or AF_INET6", 413 | @@ -1248,6 +1246,7 @@ inet_pton(af, host) 414 | #endif 415 | "Socket::inet_pton", af); 416 | } 417 | + 418 | ok = (*host != '\0') && inet_pton(af, host, &ip_address); 419 | 420 | ST(0) = sv_newmortal(); 421 | diff --git a/dist/Time-HiRes/Makefile.PL b/dist/Time-HiRes/Makefile.PL 422 | index e5ba503707..c8e792203e 100644 423 | --- a/dist/Time-HiRes/Makefile.PL 424 | +++ b/dist/Time-HiRes/Makefile.PL 425 | @@ -81,7 +81,7 @@ __EOD__ 426 | $errornull = ''; 427 | } 428 | 429 | - $cccmd = "$Config{'cc'} -o $tmp $ccflags $tmp.c @$LIBS $errornull" 430 | + $cccmd = "$Config{'cc'} -o $tmp $ccflags $Config{'ldflags'} $tmp.c @$LIBS $Config{'libs'} $errornull" 431 | unless defined $cccmd; 432 | 433 | if ($^O eq 'VMS') { 434 | diff --git a/dist/threads-shared/shared.xs b/dist/threads-shared/shared.xs 435 | index 6a7f03c289..38844079d0 100644 436 | --- a/dist/threads-shared/shared.xs 437 | +++ b/dist/threads-shared/shared.xs 438 | @@ -706,20 +706,17 @@ Perl_sharedsv_cond_timedwait(perl_cond *cond, perl_mutex *mut, double abs) 439 | 440 | CLANG_DIAG_IGNORE_STMT(-Wthread-safety); 441 | /* warning: calling function 'pthread_cond_timedwait' requires holding mutex 'mut' exclusively [-Wthread-safety-analysis] */ 442 | - switch (pthread_cond_timedwait(cond, mut, &ts)) { 443 | + const int ecode = pthread_cond_timedwait(cond, mut, &ts); 444 | CLANG_DIAG_RESTORE_STMT; 445 | - 446 | - case 0: got_it = 1; break; 447 | - case ETIMEDOUT: break; 448 | + if(ecode == 0) 449 | + got_it = 1; 450 | + else if((ecode != ETIMEDOUT) 451 | #ifdef OEMVS 452 | - case -1: 453 | - if (errno == ETIMEDOUT || errno == EAGAIN) 454 | - break; 455 | + && ((ecode != -1) || (errno != ETIMEDOUT && errno != EAGAIN)) 456 | #endif 457 | - default: 458 | - Perl_croak_nocontext("panic: cond_timedwait"); 459 | - break; 460 | - } 461 | + ) 462 | + Perl_croak_nocontext("panic: cond_timedwait"); 463 | + 464 | return (got_it); 465 | # endif /* OS2 */ 466 | # endif /* WIN32 */ 467 | diff --git a/doio.c b/doio.c 468 | index f0d451af3c..d516f76a21 100644 469 | --- a/doio.c 470 | +++ b/doio.c 471 | @@ -55,6 +55,10 @@ 472 | # define OPEN_EXCL 0 473 | #endif 474 | 475 | +#ifdef __COSMOPOLITAN__ 476 | +# include "libc/dce.h" 477 | +#endif 478 | + 479 | #define PERL_MODE_MAX 8 480 | #define PERL_FLAGS_MAX 10 481 | 482 | @@ -2512,7 +2516,16 @@ Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report) 483 | } 484 | doshell: 485 | PERL_FPU_PRE_EXEC 486 | - PerlProc_execl(PL_sh_path, "sh", "-c", cmd, (char *)NULL); 487 | +#ifdef __COSMOPOLITAN__ 488 | + if(IsWindows()) 489 | + { 490 | + PerlProc_execl("/C/Windows/System32/cmd.exe", "/C/Windows/System32/cmd.exe", "/c", cmd, (char *)NULL); 491 | + } 492 | + else 493 | +#endif 494 | + { 495 | + PerlProc_execl(PL_sh_path, "sh", "-c", cmd, (char *)NULL); 496 | + } 497 | PERL_FPU_POST_EXEC 498 | S_exec_failed(aTHX_ PL_sh_path, fd, do_report); 499 | goto leave; 500 | diff --git a/ext/Errno/Errno_pm.PL b/ext/Errno/Errno_pm.PL 501 | index ee2f4a3a92..e5902fa53c 100644 502 | --- a/ext/Errno/Errno_pm.PL 503 | +++ b/ext/Errno/Errno_pm.PL 504 | @@ -36,6 +36,33 @@ if ($Config{gccversion} ne '' && $^O eq 'MSWin32') { 505 | process_file('includes.c'); 506 | unlink 'includes.c'; 507 | } 508 | +elsif($^O eq 'cosmo') { 509 | + # use cosmo's internal api to load the errno names 510 | + open(my $cfile, '>', 'errno.c') or 511 | + die("Failed to open errno.c"); 512 | + print $cfile <<'MAGNUM'; 513 | +#include "libc/fmt/magnumstrs.internal.h" 514 | +#include 515 | +int main(void) 516 | +{ 517 | + for (unsigned i = 0; kErrnoNames[i].x != MAGNUM_TERMINATOR; ++i) 518 | + { 519 | + printf("%s\n", MAGNUM_STRING(kErrnoNames, i)); 520 | + } 521 | +} 522 | +MAGNUM 523 | + close($cfile); 524 | + system("$Config{cc} $Config{ccflags} errno.c $Config{ldflags} $Config{libs} -o errno") == 0 or die "Failed to compile errno.c"; 525 | + unlink('errno.c'); 526 | + open(my $errnoout, '-|', './errno') or die "Failed to run errno"; 527 | + while(<$errnoout>) { 528 | + chomp; 529 | + $err{$_} = 1; 530 | + } 531 | + close($errnoout); 532 | + unlink('errno'); 533 | + $err{EWOULDBLOCK} = 1; # EWOULDBLOCK isn't in the table as it's the same value as EAGAIN 534 | +} 535 | else { 536 | foreach $file (@files) { 537 | process_file($file); 538 | @@ -212,12 +239,30 @@ sub write_errno_pm { 539 | if ($IsMSWin32) { 540 | print CPPI qq[#include "../../win32/include/sys/errno2.h"\n]; 541 | } 542 | - 543 | - foreach $err (keys %err) { 544 | - print CPPI '"',$err,'" [[',$err,']]',"\n"; 545 | - } 546 | 547 | - close(CPPI); 548 | + if($^O ne 'cosmo') { 549 | + foreach $err (keys %err) { 550 | + print CPPI '"',$err,'" [[',$err,']]',"\n"; 551 | + } 552 | + close(CPPI); 553 | + } 554 | + else { 555 | + # in cosmo the preprocessor alone isn't enough to determine errno values 556 | + # instead generate and run an executable to generate the file to be fed to the preprocessor 557 | + close(CPPI); 558 | + open(my $CIN, '>', 'errno.c') or 559 | + die "Cannot open errno.c"; 560 | + print $CIN "#include \n#include \n"; 561 | + print $CIN "int main(void){\n"; 562 | + foreach my $name (keys %err) { 563 | + print $CIN ' printf("\\"'.$name.'\\" [[%d]]\n", '."$name);\n"; 564 | + } 565 | + print $CIN "}\n"; 566 | + close($CIN); 567 | + system("$Config{cc} $Config{ccflags} errno.c $Config{ldflags} $Config{libs} -o errno") == 0 or die "Failed to compile errno.c"; 568 | + system("./errno > errno.c") == 0 or die "Failed to generate errno.c"; 569 | + unlink('errno'); 570 | + } 571 | 572 | { # BeOS (support now removed) did not enter this block 573 | # invoke CPP and read the output 574 | @@ -314,9 +359,39 @@ EDQ 575 | foreach $err (@err) { 576 | print "\t$err => $err{$err},\n"; 577 | } 578 | + print " );\n"; 579 | + if($^O eq 'cosmo') { 580 | + open(my $uname, '-|', 'uname') or 581 | + die "Failed to run uname"; 582 | + my $buildos = <$uname>; 583 | + chomp $buildos; 584 | + close($uname); 585 | + print "\n".' my $buildos = '."'$buildos';\n"; 586 | +print <<'ESQ'; 587 | + # In cosmo the constants of errno change based on the current operating 588 | + # system. An XS module is provided to load them, however for miniperl's 589 | + # sake, the constants of the build os are encoded above. 590 | + if(eval "use ErrnoRuntime; 1;") { 591 | + foreach my $key (keys %err) { 592 | + $err{$key} = ErrnoRuntime::strtoerrno($key); 593 | + } 594 | + } 595 | + else { 596 | + open(my $uname, '-|', 'uname') or 597 | + die "Failed to run uname"; 598 | + my $curos = <$uname>; 599 | + close($uname); 600 | + chomp $curos; 601 | + my $failmsg = "The errno constants in Errno.pm are for miniperl on $buildos only"; 602 | + $curos eq $buildos or die $failmsg; 603 | + eval "use Config::Perl::V; 1;" or die "Failed to load Config::Perl::V"; 604 | + my $local_config = Config::Perl::V::myconfig(); 605 | + $local_config->{build}{options}{PERL_IS_MINIPERL} or die $failmsg; 606 | + } 607 | 608 | +ESQ 609 | + } 610 | print <<'ESQ'; 611 | - ); 612 | # Generate proxy constant subroutines for all the values. 613 | # Well, almost all the values. Unfortunately we can't assume that at this 614 | # point that our symbol table is empty, as code such as if the parser has 615 | diff --git a/ext/ErrnoRuntime/.gitignore b/ext/ErrnoRuntime/.gitignore 616 | new file mode 100644 617 | index 0000000000..e54624d60d 618 | --- /dev/null 619 | +++ b/ext/ErrnoRuntime/.gitignore 620 | @@ -0,0 +1 @@ 621 | +!/Makefile.PL 622 | diff --git a/ext/ErrnoRuntime/ErrnoRuntime.xs b/ext/ErrnoRuntime/ErrnoRuntime.xs 623 | new file mode 100644 624 | index 0000000000..598a8a1452 625 | --- /dev/null 626 | +++ b/ext/ErrnoRuntime/ErrnoRuntime.xs 627 | @@ -0,0 +1,34 @@ 628 | +#define PERL_NO_GET_CONTEXT 629 | +#include "EXTERN.h" 630 | +#include "perl.h" 631 | +#include "XSUB.h" 632 | +#include 633 | +#include "libc/fmt/magnumstrs.internal.h" 634 | + 635 | +MODULE = ErrnoRuntime PACKAGE = ErrnoRuntime 636 | + 637 | +IV 638 | +strtoerrno(name) 639 | + const char *name 640 | + CODE: 641 | + unsigned i; 642 | + RETVAL = 0; 643 | + for (i = 0; kErrnoNames[i].x != MAGNUM_TERMINATOR; ++i) 644 | + { 645 | + if(strcmp(name, MAGNUM_STRING(kErrnoNames, i)) == 0) 646 | + { 647 | + RETVAL = MAGNUM_NUMBER(kErrnoNames, i); 648 | + break; 649 | + } 650 | + } 651 | + // EWOULDBLOCK isn't in the table as it's the same as EAGAIN 652 | + if(strcmp(name, "EWOULDBLOCK") == 0) 653 | + { 654 | + RETVAL = EWOULDBLOCK; 655 | + } 656 | + else if(kErrnoNames[i].x == MAGNUM_TERMINATOR) 657 | + { 658 | + croak("Unknown Errno constant %s", name); 659 | + } 660 | + OUTPUT: 661 | + RETVAL 662 | \ No newline at end of file 663 | diff --git a/ext/ErrnoRuntime/Makefile.PL b/ext/ErrnoRuntime/Makefile.PL 664 | new file mode 100644 665 | index 0000000000..799e4a12bf 666 | --- /dev/null 667 | +++ b/ext/ErrnoRuntime/Makefile.PL 668 | @@ -0,0 +1,15 @@ 669 | +BEGIN { require 5.008_001 } 670 | +use ExtUtils::MakeMaker; 671 | + 672 | +# this module only needed and implemented for cosmo right now 673 | +$^O eq 'cosmo' or die "OS unsupported"; 674 | + 675 | +WriteMakefile( 676 | + VERSION_FROM => "lib/ErrnoRuntime.pm", 677 | + NAME => "ErrnoRuntime", 678 | + OBJECT => '$(O_FILES)', 679 | + ABSTRACT => 'Load Errno constants at runtime', 680 | + AUTHOR => 'Gavin Hayes ', 681 | + PREREQ_PM => { 682 | + }, 683 | +); 684 | diff --git a/ext/ErrnoRuntime/lib/ErrnoRuntime.pm b/ext/ErrnoRuntime/lib/ErrnoRuntime.pm 685 | new file mode 100644 686 | index 0000000000..f53859e5d3 687 | --- /dev/null 688 | +++ b/ext/ErrnoRuntime/lib/ErrnoRuntime.pm 689 | @@ -0,0 +1,68 @@ 690 | +package ErrnoRuntime; 691 | + 692 | +use 5.020002; 693 | +use strict; 694 | +use warnings; 695 | +our $VERSION = '0.0'; 696 | + 697 | +require Exporter; 698 | + 699 | +our @ISA = qw(Exporter); 700 | + 701 | +# Items to export into callers namespace by default. Note: do not export 702 | +# names by default without a very good reason. Use EXPORT_OK instead. 703 | +# Do not simply export all your public functions/methods/constants. 704 | + 705 | +# This allows declaration use ErrnoRuntime ':all'; 706 | +# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK 707 | +# will save memory. 708 | +our %EXPORT_TAGS = ( 'all' => [ qw( 709 | + 710 | +) ] ); 711 | + 712 | +our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); 713 | + 714 | +our @EXPORT = qw( 715 | + 716 | +); 717 | + 718 | +require XSLoader; 719 | +XSLoader::load('ErrnoRuntime', $VERSION); 720 | + 721 | +# Preloaded methods go here. 722 | + 723 | +1; 724 | + 725 | +__END__ 726 | + 727 | +=pod 728 | + 729 | +=encoding utf-8 730 | + 731 | +=head1 NAME 732 | + 733 | +ErrnoRuntime - XS extension module for loading errno values at 734 | +runtime 735 | + 736 | +=head1 SYNOPSIS 737 | + 738 | + use ErrnoRuntime; 739 | + 740 | +=head1 AUTHOR 741 | + 742 | +Gavin Hayes, C<< >> 743 | + 744 | +=head1 SUPPORT AND DOCUMENTATION 745 | + 746 | +You can find documentation for this module with the perldoc command. 747 | + 748 | + perldoc ErrnoRuntime 749 | + 750 | +=head1 LICENSE AND COPYRIGHT 751 | + 752 | +This software is copyright (c) 2022 by Gavin Hayes. 753 | + 754 | +This is free software; you can redistribute it and/or modify it under 755 | +the same terms as the Perl 5 programming language system itself. 756 | + 757 | +=cut 758 | diff --git a/ext/POSIX/t/sigaction.t b/ext/POSIX/t/sigaction.t 759 | index 024c66a147..2741c895ed 100644 760 | --- a/ext/POSIX/t/sigaction.t 761 | +++ b/ext/POSIX/t/sigaction.t 762 | @@ -51,7 +51,7 @@ ok($oldaction->{MASK}->ismember(SIGUSR1), "SIGUSR1 ismember MASK"); 763 | 764 | SKIP: { 765 | skip("sigaction() thinks different in $^O", 1) 766 | - if $^O eq 'linux' || $^O eq 'unicos'; 767 | + if $^O eq 'linux' || $^O eq 'unicos' || $^O eq 'cosmo'; 768 | is($oldaction->{FLAGS}, 0); 769 | } 770 | 771 | diff --git a/hints/cosmo.sh b/hints/cosmo.sh 772 | new file mode 100644 773 | index 0000000000..657cd3246c 774 | --- /dev/null 775 | +++ b/hints/cosmo.sh 776 | @@ -0,0 +1,27 @@ 777 | +#! /bin/sh 778 | +# cosmo.sh - hints for building perl using the Cosmopolitan Libc 779 | +# 780 | + 781 | +test -d "$COSMO_REPO" || exit 1; 782 | +COSMO_APE_LOADER=${COSMO_APE_LOADER:="ape-no-modify-self.o"} 783 | + 784 | +usedl='undef' 785 | +usenm='false' 786 | +so='none' 787 | +osname='cosmo' 788 | +osvers='' 789 | +libpth='none' 790 | +#incpth= 791 | +#incpath= 792 | +#usrinc= 793 | +d_procselfexe='undef' 794 | +locincpth='' 795 | +usrinc="$COSMO_REPO/libc/isystem" 796 | +cc="$COSMO_REPO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" 797 | +ccflags="-static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone -fno-omit-frame-pointer -fno-stack-protector -pg -mnop-mcount -mno-tls-direct-seg-refs -I $COSMO_REPO -include $COSMO_REPO/libc/integral/normalize.inc -isystem $COSMO_REPO/libc/isystem" 798 | +ldflags="-static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone -fno-omit-frame-pointer -fno-stack-protector -pg -mnop-mcount -mno-tls-direct-seg-refs -Wl,--gc-sections -fuse-ld=bfd -Wl,-T,$COSMO_REPO/o/$COSMO_MODE/ape/public/ape.lds $COSMO_REPO/o/$COSMO_MODE/libc/crt/crt.o $COSMO_REPO/o/$COSMO_MODE/ape/$COSMO_APE_LOADER" 799 | +libs="$COSMO_REPO/o/$COSMO_MODE/cosmopolitan.a" 800 | +#noextensions='' 801 | +unset COSMO_REPO 802 | +unset COSMO_MODE 803 | +unset COSMO_APE_LOADER 804 | diff --git a/lib/.gitignore b/lib/.gitignore 805 | index cb6a26cfcc..8d99235088 100644 806 | --- a/lib/.gitignore 807 | +++ b/lib/.gitignore 808 | @@ -37,6 +37,7 @@ 809 | /Encode/ 810 | /Env.pm 811 | /Errno.pm 812 | +/ErrnoRuntime.pm 813 | /Exporter.pm 814 | /Exporter/ 815 | /ExtUtils/CBuilder.pm 816 | diff --git a/patchlevel.h b/patchlevel.h 817 | index 52a8d53879..d52e867594 100644 818 | --- a/patchlevel.h 819 | +++ b/patchlevel.h 820 | @@ -157,6 +157,13 @@ hunk. 821 | # endif 822 | static const char * const local_patches[] = { 823 | NULL 824 | + ,"G4Vi:cosmo/c473e9-73ecc6c - https://github.com/G4Vi/perl5/compare/c473e9~1...73ecc6c various changes to support building with the Cosmopolitan Libc" 825 | + ,"G4Vi:cosmo/2fb034f - https://github.com/G4Vi/perl5/commit/2fb034ffb02db2b3ac09706c954704930c620c0b fix Time-HiRes Configure to work for cosmopolitan" 826 | + ,"G4Vi:cosmo/3643b8b - https://github.com/G4Vi/perl5/commit/3643b8bd369ea1e8715a27ce8821c8e70f2c17e0 add cosmo as Unix in Perl::OSType (fixes Module::Build)" 827 | + ,"G4Vi:cosmo/e3d8537 - https://github.com/G4Vi/perl5/commit/e3d853703f5c7c951a14e1eed186105cc0e0b7e3 s/perl.elf$/perl.com.dbg/ as perl.com.dbg is useful for --ftrace" 828 | + ,"G4Vi:cosmo/7138814 - https://github.com/G4Vi/perl5/commit/713881482f9968f4960090d2699bc4cb4a46dc94 update for cosmo 3.0.2, new ape copying" 829 | + ,"G4Vi:cosmo/ecf4f8d - https://github.com/G4Vi/perl5/commit/ecf4f8ddb6aaad4544b8e16541c52b4dc570b491 revert a no longer needed switch rewrite" 830 | + ,"G4Vi:cosmo/022d57c - https://github.com/G4Vi/perl5/commit/022d57c45c0005ea8a1d9a5b8fe7eb7eb7b29225 revert ecf4f8d and 7138814" 831 | #ifdef PERL_GIT_UNCOMMITTED_CHANGES 832 | ,"uncommitted-changes" 833 | #endif 834 | diff --git a/pod/.gitignore b/pod/.gitignore 835 | index a16aaa9a5f..b731fa2fd6 100644 836 | --- a/pod/.gitignore 837 | +++ b/pod/.gitignore 838 | @@ -4,6 +4,7 @@ 839 | /perlandroid.pod 840 | /perlbs2000.pod 841 | /perlcn.pod 842 | +/perlcosmo.pod 843 | /perlcygwin.pod 844 | /perldos.pod 845 | /perlfreebsd.pod 846 | diff --git a/pod/perl.pod b/pod/perl.pod 847 | index 6a14569758..5db5882a9c 100644 848 | --- a/pod/perl.pod 849 | +++ b/pod/perl.pod 850 | @@ -277,6 +277,7 @@ aux h2ph h2xs perlbug pl2pm pod2html pod2man splain xsubpp 851 | perlamiga Perl notes for AmigaOS 852 | perlandroid Perl notes for Android 853 | perlbs2000 Perl notes for POSIX-BC BS2000 854 | + perlcosmo Perl notes for the Cosmopolitan Libc 855 | perlcygwin Perl notes for Cygwin 856 | perlfreebsd Perl notes for FreeBSD 857 | perlhaiku Perl notes for Haiku 858 | -------------------------------------------------------------------------------- /share/5.36-cosmo3.patch: -------------------------------------------------------------------------------- 1 | diff --git a/.mailmap b/.mailmap 2 | index 72a8a4d6a7..37c3ffce5f 100644 3 | --- a/.mailmap 4 | +++ b/.mailmap 5 | @@ -646,6 +646,7 @@ Gabor Szabo Gabor Szabo 6 | Garry T. Williams Garry T. Williams 7 | Gary Clark Gary Clark 8 | Gary L. Armstrong Gary L. Armstrong 9 | +Gavin Hayes Gavin Hayes 10 | Gavin Shelley Gavin Shelley 11 | Gene Sullivan gene sullivan 12 | Gene Sullivan Gene Sullivan 13 | diff --git a/AUTHORS b/AUTHORS 14 | index 8f25e9d835..8fcde9e4e2 100644 15 | --- a/AUTHORS 16 | +++ b/AUTHORS 17 | @@ -482,6 +482,7 @@ Garry T. Williams 18 | Gary Clark 19 | Gary L. Armstrong 20 | Gary Ng <71564.1743@compuserve.com> 21 | +Gavin Hayes 22 | Gavin Shelley 23 | Gene Sullivan 24 | Geoffrey F. Green 25 | diff --git a/Configure b/Configure 26 | index 67e990217d..bedad1da43 100755 27 | --- a/Configure 28 | +++ b/Configure 29 | @@ -2744,7 +2744,7 @@ int main(int argc, char *argv[]) { 30 | return 0; 31 | } 32 | EOM 33 | - if $cc -o try $ccflags $ldflags try.c; then 34 | + if $cc -o try $ccflags $ldflags try.c $libs; then 35 | : 36 | else 37 | echo "Uh-oh, the C compiler '$cc' doesn't seem to be working." >&4 38 | @@ -2816,7 +2816,7 @@ int main(int argc, char *argv[]) { 39 | return 0; 40 | } 41 | EOM 42 | - if $cc -o try $ccflags $ldflags try.c; then 43 | + if $cc -o try $ccflags $ldflags try.c $libs; then 44 | : 45 | else 46 | if $test X"$despair" = Xyes; then 47 | @@ -3665,6 +3665,11 @@ EOM 48 | fi 49 | fi 50 | 51 | + if [ $COSMOCC ]; then 52 | + osname='cosmo' 53 | + osvers='' 54 | + fi 55 | + 56 | case "$targetarch" in 57 | '') ;; 58 | *) hostarch=$osname 59 | @@ -4576,7 +4581,7 @@ int main() { 60 | return(0); 61 | } 62 | EOM 63 | -if $cc -o try $ccflags $ldflags try.c; then 64 | +if $cc -o try $ccflags $ldflags try.c $libs; then 65 | gccversion=`$run ./try` 66 | case "$gccversion" in 67 | '') echo "You are not using GNU cc." ;; 68 | @@ -4697,7 +4702,7 @@ int main(int argc, char **argv) { 69 | EOCP 70 | c99_for=no 71 | for flag in '' '-std=gnu99' '-std=c99'; do 72 | - if $cc -o try $flag $ccflags $ldflags try.c 2>/dev/null && ./try; then 73 | + if $cc -o try $flag $ccflags $ldflags try.c $libs 2>/dev/null && ./try; then 74 | c99_for="$flag" 75 | break; 76 | fi 77 | @@ -5401,7 +5406,7 @@ echo " "; 78 | echo "Checking if your compiler accepts $flag" >&4; 79 | [ "X$sysroot" != "X" ] && echo "For sysroot = $sysroot"; 80 | echo "int main(void) { return 0; }" > gcctest.c; 81 | -if $cc $_sysroot -O2 $flag -o gcctest gcctest.c 2>gcctest.out && $run ./gcctest; then 82 | +if $cc $_sysroot -O2 $flag -o gcctest $ccflags $ldflags gcctest.c $libs 2>gcctest.out && $run ./gcctest; then 83 | echo "Yes, it does." >&4; 84 | if $test -s gcctest.out ; then 85 | echo "But your platform does not like it:"; 86 | @@ -23699,6 +23704,8 @@ else 87 | if $test -s ccsym.own; then 88 | $test "$also" && echo " " 89 | echo "Your C compiler ${also}defines the following cpp symbols:" 90 | + echo "LARGEFILE_SOURCE" > ccsym.own 91 | + echo "DONT_USE_BUILTIN_SETJMP" >> ccsym.own 92 | $sed -e 's/\(..*\)=1/\1/' ccsym.own 93 | $sed -e 's/\(..*\)=.*/\1/' ccsym.own | $uniq >>Cppsym.true 94 | ccsymbols=`$cat ccsym.own` 95 | diff --git a/MANIFEST b/MANIFEST 96 | index c2057ee452..8e9795c82d 100644 97 | --- a/MANIFEST 98 | +++ b/MANIFEST 99 | @@ -4303,6 +4303,9 @@ ext/Errno/ChangeLog Errno changes 100 | ext/Errno/Errno_pm.PL Errno perl module create script 101 | ext/Errno/Makefile.PL Errno extension makefile writer 102 | ext/Errno/t/Errno.t See if Errno works 103 | +ext/ErrnoRuntime/ErrnoRuntime.xs ErrnoRuntime extension implementation 104 | +ext/ErrnoRuntime/lib/ErrnoRuntime.pm ErrnoRuntime extension Perl module 105 | +ext/ErrnoRuntime/Makefile.PL ErrnoRuntime extension makefile writer 106 | ext/ExtUtils-Miniperl/lib/ExtUtils/Miniperl.pm Writes {mini,}perlmain.c 107 | ext/Fcntl/Fcntl.pm Fcntl extension Perl module 108 | ext/Fcntl/Fcntl.xs Fcntl extension external subroutines 109 | @@ -4765,6 +4768,7 @@ hints/broken-db.msg Warning message for systems with broken DB library 110 | hints/bsdos.sh Hints for named architecture 111 | hints/catamount.sh Hints for named architecture 112 | hints/convexos.sh Hints for named architecture 113 | +hints/cosmo.sh Hints for named architecture 114 | hints/cxux.sh Hints for named architecture 115 | hints/cygwin.sh Hints for named architecture 116 | hints/darwin.sh Hints for named architecture 117 | @@ -5517,6 +5521,7 @@ README.amiga Perl notes for AmigaOS 118 | README.android Perl notes for Android 119 | README.bs2000 Perl notes for POSIX-BC BS2000 120 | README.cn Perl for Simplified Chinese (in UTF-8) 121 | +README.cosmo Perl notes for the Cosmopolitan Libc 122 | README.cygwin Perl notes for Cygwin 123 | README.freebsd Perl notes for FreeBSD 124 | README.haiku Perl notes for Haiku 125 | diff --git a/Makefile.SH b/Makefile.SH 126 | index cb0efb32ab..0d8e7b2094 100755 127 | --- a/Makefile.SH 128 | +++ b/Makefile.SH 129 | @@ -999,6 +999,19 @@ lib/buildcustomize.pl: $& $(miniperl_objs) write_buildcustomize.pl 130 | $(miniperl_objs) $(libs) 131 | $(LDLIBPTH) ./miniperl$(HOST_EXE_EXT) -w -Ilib -Idist/Exporter/lib -MExporter -e '' || sh -c 'echo >&2 Failed to build miniperl. Please run make minitest; exit 1' 132 | $(MINIPERL) -f write_buildcustomize.pl 133 | +!NO!SUBS! 134 | + ;; 135 | + cosmo*) 136 | + $spitshell >>$Makefile <<'!NO!SUBS!' 137 | +lib/buildcustomize.pl: $& $(miniperl_dep) write_buildcustomize.pl 138 | + -@rm -f miniperl.xok 139 | + $(CC) $(CLDFLAGS) -o miniperl.com \ 140 | + $(miniperl_objs) $(libs) 141 | + cp miniperl.com $(MINIPERL_EXE) 142 | + chmod -w miniperl.com 143 | + ./miniperl --assimilate || true 144 | + $(LDLIBPTH) ./miniperl$(HOST_EXE_EXT) -w -Ilib -Idist/Exporter/lib -MExporter -e '' || sh -c 'echo >&2 Failed to build miniperl. Please run make minitest; exit 1' 145 | + $(MINIPERL) -f write_buildcustomize.pl 146 | !NO!SUBS! 147 | ;; 148 | *) 149 | @@ -1054,7 +1067,13 @@ $(PERL_EXE): $& $(perlmain_dep) $(LIBPERL) $(static_ext) ext.libs $(PERLEXPORT) 150 | ;; 151 | esac 152 | ;; 153 | - 154 | + cosmo) $spitshell >>$Makefile <<'!NO!SUBS!' 155 | + $(SHRPENV) $(CC) -o perl.com $(CLDFLAGS) $(CCDLFLAGS) $(perlmain_objs) $(static_ext) $(LLIBPERL) `cat ext.libs` $(libs) 156 | + cp perl.com $(PERL_EXE) 157 | + chmod -w perl.com 158 | + ./perl --assimilate || true 159 | +!NO!SUBS! 160 | + ;; 161 | *) $spitshell >>$Makefile <<'!NO!SUBS!' 162 | $(SHRPENV) $(CC) -o perl $(CLDFLAGS) $(CCDLFLAGS) $(perlmain_objs) $(static_ext) $(LLIBPERL) `cat ext.libs` $(libs) 163 | !NO!SUBS! 164 | diff --git a/Porting/Maintainers.pl b/Porting/Maintainers.pl 165 | index 1413ce02fc..49200f34b7 100755 166 | --- a/Porting/Maintainers.pl 167 | +++ b/Porting/Maintainers.pl 168 | @@ -1385,6 +1385,7 @@ use File::Glob qw(:case); 169 | ext/Devel-Peek/ 170 | ext/DynaLoader/ 171 | ext/Errno/ 172 | + ext/ErrnoRuntime/ 173 | ext/ExtUtils-Miniperl/ 174 | ext/Fcntl/ 175 | ext/File-DosGlob/ 176 | diff --git a/README.cosmo b/README.cosmo 177 | new file mode 100644 178 | index 0000000000..e5b5de8952 179 | --- /dev/null 180 | +++ b/README.cosmo 181 | @@ -0,0 +1,87 @@ 182 | +If you read this file _as_is_, just ignore the funny characters you see. 183 | +It is written in the POD format (see pod/perlpod.pod) which is specially 184 | +designed to be readable as is. 185 | + 186 | +=head1 NAME 187 | + 188 | +perlcosmo - Build-once run-anywhere Perl using the Cosmopolitan Libc 189 | + 190 | +=head1 DESCRIPTION 191 | + 192 | +The cosmo platform addition eases building Perl with the Cosmopolitan 193 | +Libc. When you build with the Cosmopolitan Libc, the libc is the 194 | +platform as the Cosmopolitan Libc targets building simultaneous support 195 | +for multiple operating systems (Unixes, Windows, etc) into the same 196 | +binary. 197 | + 198 | +To get the most benefits of the cosmo platform, you likely want to 199 | +build Actually Portable Perl (APPerl) instead of this directly. See 200 | +L ; APPerl Manager (apperlm) includes a front-end 201 | +for building perl from source with the Cosmopolitan Libc. The 202 | +instructions in this document only cover building perl, not building or 203 | +packaging into APPerl (single executable perl with perl modules 204 | +embedded inside). 205 | + 206 | +=head1 BUILD 207 | + 208 | +Download the Cosmopolitan Libc and build with the desired MODE: 209 | + 210 | + git clone https://github.com/jart/cosmopolitan ../cosmopolitan 211 | + make -C ../cosmopolitan -j4 MODE= 212 | + 213 | +Run Configure, but with some environment variables to point it at 214 | +cosmopolitan; update COSMO_MODE to the MODE you set before and 215 | +COSMO_REPO to the absolute path of the cosmopolitan repo. Then, make 216 | +and install like usual. 217 | + 218 | + COSMO_MODE= COSMO_REPO="/home/gavin/cosmopolitan" ./Configure -de 219 | + make 220 | + make install 221 | + 222 | +Note the installed binary is assimilated (see Cosmopolitan Libc 223 | +--assimilate flag), meaning it only runs on the current operating 224 | +system. The perl.com in the perl repo, however, is actually portable 225 | +and will run on several operating systems. For a solution that builds 226 | +on this, by packaging perl modules and scripts inside of the executable 227 | +and more, see L. 228 | + 229 | +=head1 KNOWN PROBLEMS 230 | + 231 | +cosmo perl is a work in progress, many major issues are present. 232 | + 233 | +=over 4 234 | + 235 | +=item * 236 | + 237 | +C behavior when a shell is required, depends on the currently 238 | +running operating system. On most systems it uses, C, but on 239 | +Windows it uses C. Therefore, it's still hard to use portably. 240 | +However, it is sufficient for pulling up a pager for L . 241 | + 242 | +=item * 243 | + 244 | +After building, only Pure Perl modules may be added as perl is built 245 | +statically. 246 | + 247 | +=item * 248 | + 249 | +Some magic only works when the binary is assimilated. For example, 250 | +modifying C<$0>. Running with C<--assimilate> will bind the binary to 251 | +the current operating system. 252 | + 253 | +=back 254 | + 255 | +=head1 ACKNOWLEDGEMENTS 256 | + 257 | +The L 258 | +contributors, especially L and 259 | +L. 260 | +Gautham's 261 | +L 262 | +to the Cosmopolitan Libc inspired this port. 263 | + 264 | +=head1 CONTACT 265 | + 266 | +The port in-progress is being done by Gavin Hayes 267 | + 268 | +Last update: 2022-10-11 269 | diff --git a/caretx.c b/caretx.c 270 | index 3d11877037..211a2e89a7 100644 271 | --- a/caretx.c 272 | +++ b/caretx.c 273 | @@ -40,6 +40,10 @@ 274 | # include 275 | #endif 276 | 277 | +#if defined(__COSMOPOLITAN__) 278 | +# include "libc/cosmo.h" 279 | +#endif 280 | + 281 | void 282 | Perl_set_caret_X(pTHX) { 283 | GV* tmpgv = gv_fetchpvs("\030", GV_ADD|GV_NOTQUAL, SVt_PV); /* $^X */ 284 | @@ -55,6 +59,9 @@ Perl_set_caret_X(pTHX) { 285 | sv_setpv(caret_x, ansi); 286 | win32_free(ansi); 287 | return; 288 | +#elif defined(__COSMOPOLITAN__) 289 | + sv_setpv(caret_x, GetProgramExecutableName()); 290 | + return; 291 | #else 292 | /* We can try a platform-specific one if possible; if it fails, or we 293 | * aren't running on a suitable platform, we'll fall back to argv[0]. */ 294 | diff --git a/configpm b/configpm 295 | index 94a4778037..2f7ab82600 100755 296 | --- a/configpm 297 | +++ b/configpm 298 | @@ -585,6 +585,13 @@ $heavy_txt .= join('', 299 | } @v_others, @v_forced 300 | ) . "!END!\n"; 301 | 302 | +if ($^O eq 'cosmo') { 303 | +$heavy_txt .= <<'EOT'; 304 | + 305 | +s/perlpath=.+/perlpath='$^X'/; 306 | +EOT 307 | +} 308 | + 309 | # Only need the dynamic byteorder code in Config.pm if 'byteorder' is one of 310 | # the precached keys 311 | if ($Common{byteorder}) { 312 | diff --git a/cpan/ExtUtils-Constant/lib/ExtUtils/Constant/ProxySubs.pm b/cpan/ExtUtils-Constant/lib/ExtUtils/Constant/ProxySubs.pm 313 | index 0aee5233fe..cd17c1c86f 100644 314 | --- a/cpan/ExtUtils-Constant/lib/ExtUtils/Constant/ProxySubs.pm 315 | +++ b/cpan/ExtUtils-Constant/lib/ExtUtils/Constant/ProxySubs.pm 316 | @@ -406,13 +406,14 @@ EOC 317 | 318 | print $c_fh "struct $struct_type $struct;\n"; 319 | 320 | + my $structtypetype = $type ? 'static struct' : 'static const struct'; 321 | print $struct_fh <<"EOBOOT"; 322 | 323 | - static const struct $struct_type $array_name\[] = 324 | + $structtypetype $struct_type $array_name\[] = 325 | { 326 | EOBOOT 327 | 328 | - 329 | + my @valuestowrite; 330 | foreach my $item (@{$found->{$type}}) { 331 | my ($name, $namelen, $value, $macro) 332 | = $self->name_len_value_macro($item); 333 | @@ -429,8 +430,8 @@ EOBOOT 334 | } else { 335 | print $struct_fh $ifdef; 336 | } 337 | - print $struct_fh " { ", join (', ', "\"$name\"", $namelen, 338 | - &$type_to_value($value)), 339 | + push @valuestowrite, &$type_to_value($value); 340 | + print $struct_fh " { ", join (', ', "\"$name\"", $namelen), 341 | " },\n", 342 | $self->macro_to_endif($macro); 343 | } 344 | @@ -438,6 +439,28 @@ EOBOOT 345 | # Terminate the list with a NULL 346 | print $struct_fh " { NULL, 0", (", 0" x $number_of_args), " } };\n"; 347 | 348 | + if($type) { 349 | + print $struct_fh "{\nunsigned i = 0;\n"; 350 | + foreach my $item (@{$found->{$type}}) { 351 | + my ($name, $namelen, $value, $macro) = $self->name_len_value_macro($item); 352 | + my $ifdef = $self->macro_to_ifdef($macro); 353 | + if (!$ifdef && $item->{invert_macro}) { 354 | + carp("Attempting to supply a default for '$name' which has no conditional macro"); 355 | + next; 356 | + } 357 | + if ($item->{invert_macro}) { 358 | + print $struct_fh $self->macro_to_ifndef($macro); 359 | + print $struct_fh 360 | + " /* This is the default value: */\n" if $type; 361 | + } else { 362 | + print $struct_fh $ifdef; 363 | + } 364 | + print $struct_fh $array_name,"[i++].value = ". (shift @valuestowrite) . ";\n"; 365 | + print $struct_fh $self->macro_to_endif($macro); 366 | + } 367 | + print $struct_fh "}\n"; 368 | + } 369 | + 370 | print $xs_fh <<"EOBOOT" if $type; 371 | const struct $struct_type *$iterator{$type} = $array_name; 372 | EOBOOT 373 | diff --git a/cpan/Perl-OSType/lib/Perl/OSType.pm b/cpan/Perl-OSType/lib/Perl/OSType.pm 374 | index a72dd024b5..a0f2606137 100644 375 | --- a/cpan/Perl-OSType/lib/Perl/OSType.pm 376 | +++ b/cpan/Perl-OSType/lib/Perl/OSType.pm 377 | @@ -55,6 +55,7 @@ my %OSTYPES = qw( 378 | nto Unix 379 | qnx Unix 380 | android Unix 381 | + cosmo Unix 382 | 383 | dos Windows 384 | MSWin32 Windows 385 | diff --git a/cpan/Socket/Socket.xs b/cpan/Socket/Socket.xs 386 | index b4bccb796d..3ec940c3e6 100644 387 | --- a/cpan/Socket/Socket.xs 388 | +++ b/cpan/Socket/Socket.xs 389 | @@ -1165,7 +1165,7 @@ inet_ntop(af, ip_address_sv) 390 | STRLEN addrlen; 391 | #ifdef AF_INET6 392 | struct in6_addr addr; 393 | - char str[INET6_ADDRSTRLEN]; 394 | + char str[65]; 395 | #else 396 | struct in_addr addr; 397 | char str[INET_ADDRSTRLEN]; 398 | @@ -1177,20 +1177,19 @@ inet_ntop(af, ip_address_sv) 399 | 400 | ip_address = SvPVbyte(ip_address_sv, addrlen); 401 | 402 | - switch(af) { 403 | - case AF_INET: 404 | - if(addrlen != 4) 405 | + if(af == AF_INET) { 406 | + if(addrlen != 4) 407 | croak("Bad address length for Socket::inet_ntop on AF_INET;" 408 | " got %" UVuf ", should be 4", (UV)addrlen); 409 | - break; 410 | + } 411 | #ifdef AF_INET6 412 | - case AF_INET6: 413 | - if(addrlen != 16) 414 | + else if(af == AF_INET6) { 415 | + if(addrlen != 16) 416 | croak("Bad address length for Socket::inet_ntop on AF_INET6;" 417 | " got %" UVuf ", should be 16", (UV)addrlen); 418 | - break; 419 | + } 420 | #endif 421 | - default: 422 | + else { 423 | croak("Bad address family for %s, got %d, should be" 424 | #ifdef AF_INET6 425 | " either AF_INET or AF_INET6", 426 | @@ -1230,16 +1229,15 @@ inet_pton(af, host) 427 | struct in_addr ip_address; 428 | #endif 429 | 430 | - switch(af) { 431 | - case AF_INET: 432 | - addrlen = 4; 433 | - break; 434 | + if(af == AF_INET) { 435 | + addrlen = 4; 436 | + } 437 | #ifdef AF_INET6 438 | - case AF_INET6: 439 | - addrlen = 16; 440 | - break; 441 | + else if(af == AF_INET6) { 442 | + addrlen = 16; 443 | + } 444 | #endif 445 | - default: 446 | + else { 447 | croak("Bad address family for %s, got %d, should be" 448 | #ifdef AF_INET6 449 | " either AF_INET or AF_INET6", 450 | @@ -1248,6 +1246,7 @@ inet_pton(af, host) 451 | #endif 452 | "Socket::inet_pton", af); 453 | } 454 | + 455 | ok = (*host != '\0') && inet_pton(af, host, &ip_address); 456 | 457 | ST(0) = sv_newmortal(); 458 | diff --git a/dist/IO/t/cachepropagate-unix.t b/dist/IO/t/cachepropagate-unix.t 459 | index 718d01da1d..8024a10474 100644 460 | --- a/dist/IO/t/cachepropagate-unix.t 461 | +++ b/dist/IO/t/cachepropagate-unix.t 462 | @@ -50,7 +50,7 @@ my $p = $listener->protocol(); 463 | # This is a TODO instead of a skip so if these ever implement SO_PROTOCOL 464 | # we'll be notified about the passing TODO so the test can be updated. 465 | local $TODO = "$^O doesn't support SO_PROTOCOL on AF_UNIX" 466 | - if $^O =~ /^(netbsd|darwin|cygwin|hpux|solaris|dragonfly|os390|gnu)$/; 467 | + if $^O =~ /^(netbsd|darwin|cygwin|hpux|solaris|dragonfly|os390|gnu|cosmo)$/; 468 | ok(defined($p), 'protocol defined'); 469 | } 470 | my $d = $listener->sockdomain(); 471 | @@ -105,7 +105,7 @@ SKIP: { 472 | { 473 | # see comment above 474 | local $TODO = "$^O doesn't support SO_PROTOCOL on AF_UNIX" 475 | - if $^O =~ /^(netbsd|darwin|cygwin|hpux|solaris|dragonfly|os390|gnu)$/; 476 | + if $^O =~ /^(netbsd|darwin|cygwin|hpux|solaris|dragonfly|os390|gnu|cosmo)$/; 477 | ok(defined($p), 'protocol defined'); 478 | } 479 | $d = $listener->sockdomain(); 480 | diff --git a/dist/Time-HiRes/Makefile.PL b/dist/Time-HiRes/Makefile.PL 481 | index e5ba503707..c8e792203e 100644 482 | --- a/dist/Time-HiRes/Makefile.PL 483 | +++ b/dist/Time-HiRes/Makefile.PL 484 | @@ -81,7 +81,7 @@ __EOD__ 485 | $errornull = ''; 486 | } 487 | 488 | - $cccmd = "$Config{'cc'} -o $tmp $ccflags $tmp.c @$LIBS $errornull" 489 | + $cccmd = "$Config{'cc'} -o $tmp $ccflags $Config{'ldflags'} $tmp.c @$LIBS $Config{'libs'} $errornull" 490 | unless defined $cccmd; 491 | 492 | if ($^O eq 'VMS') { 493 | diff --git a/dist/threads-shared/shared.xs b/dist/threads-shared/shared.xs 494 | index 6a7f03c289..38844079d0 100644 495 | --- a/dist/threads-shared/shared.xs 496 | +++ b/dist/threads-shared/shared.xs 497 | @@ -706,20 +706,17 @@ Perl_sharedsv_cond_timedwait(perl_cond *cond, perl_mutex *mut, double abs) 498 | 499 | CLANG_DIAG_IGNORE_STMT(-Wthread-safety); 500 | /* warning: calling function 'pthread_cond_timedwait' requires holding mutex 'mut' exclusively [-Wthread-safety-analysis] */ 501 | - switch (pthread_cond_timedwait(cond, mut, &ts)) { 502 | + const int ecode = pthread_cond_timedwait(cond, mut, &ts); 503 | CLANG_DIAG_RESTORE_STMT; 504 | - 505 | - case 0: got_it = 1; break; 506 | - case ETIMEDOUT: break; 507 | + if(ecode == 0) 508 | + got_it = 1; 509 | + else if((ecode != ETIMEDOUT) 510 | #ifdef OEMVS 511 | - case -1: 512 | - if (errno == ETIMEDOUT || errno == EAGAIN) 513 | - break; 514 | + && ((ecode != -1) || (errno != ETIMEDOUT && errno != EAGAIN)) 515 | #endif 516 | - default: 517 | - Perl_croak_nocontext("panic: cond_timedwait"); 518 | - break; 519 | - } 520 | + ) 521 | + Perl_croak_nocontext("panic: cond_timedwait"); 522 | + 523 | return (got_it); 524 | # endif /* OS2 */ 525 | # endif /* WIN32 */ 526 | diff --git a/doio.c b/doio.c 527 | index f0d451af3c..c7e76d0512 100644 528 | --- a/doio.c 529 | +++ b/doio.c 530 | @@ -55,6 +55,11 @@ 531 | # define OPEN_EXCL 0 532 | #endif 533 | 534 | +#ifdef __COSMOPOLITAN__ 535 | +# include "libc/dce.h" 536 | +# include "libc/runtime/runtime.h" 537 | +#endif 538 | + 539 | #define PERL_MODE_MAX 8 540 | #define PERL_FLAGS_MAX 10 541 | 542 | @@ -2512,7 +2517,24 @@ Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report) 543 | } 544 | doshell: 545 | PERL_FPU_PRE_EXEC 546 | - PerlProc_execl(PL_sh_path, "sh", "-c", cmd, (char *)NULL); 547 | +#ifdef __COSMOPOLITAN__ 548 | + if(IsWindows()) 549 | + { 550 | + // hack for perldoc 551 | + static const char paginate_cmd_start[] = "more \"/tmp/"; 552 | + if (strncmp(paginate_cmd_start, cmd, sizeof(paginate_cmd_start)-1) == 0) { 553 | + cmd[strlen(cmd)-1] = '\0'; 554 | + __paginate_file(1, cmd + 6); 555 | + exit(0); 556 | + } 557 | + 558 | + PerlProc_execl("/C/Windows/System32/cmd.exe", "/C/Windows/System32/cmd.exe", "/c", cmd, (char *)NULL); 559 | + } 560 | + else 561 | +#endif 562 | + { 563 | + PerlProc_execl(PL_sh_path, "sh", "-c", cmd, (char *)NULL); 564 | + } 565 | PERL_FPU_POST_EXEC 566 | S_exec_failed(aTHX_ PL_sh_path, fd, do_report); 567 | goto leave; 568 | diff --git a/ext/DynaLoader/t/DynaLoader.t b/ext/DynaLoader/t/DynaLoader.t 569 | index 11b37b5c4e..7cd7769d38 100644 570 | --- a/ext/DynaLoader/t/DynaLoader.t 571 | +++ b/ext/DynaLoader/t/DynaLoader.t 572 | @@ -119,7 +119,7 @@ SKIP: { 573 | # (not at least by that name) that the dl_findfile() 574 | # could find. 575 | skip( "dl_findfile test not appropriate on $^O", 1 ) 576 | - if $^O =~ /(win32|vms|openbsd|bitrig|cygwin|vos|os390)/i; 577 | + if $^O =~ /(win32|vms|openbsd|bitrig|cygwin|vos|os390|cosmo)/i; 578 | # Play safe and only try this test if this system 579 | # looks pretty much Unix-like. 580 | skip( "dl_findfile test not appropriate on $^O", 1 ) 581 | diff --git a/ext/Errno/Errno_pm.PL b/ext/Errno/Errno_pm.PL 582 | index ee2f4a3a92..e5902fa53c 100644 583 | --- a/ext/Errno/Errno_pm.PL 584 | +++ b/ext/Errno/Errno_pm.PL 585 | @@ -36,6 +36,33 @@ if ($Config{gccversion} ne '' && $^O eq 'MSWin32') { 586 | process_file('includes.c'); 587 | unlink 'includes.c'; 588 | } 589 | +elsif($^O eq 'cosmo') { 590 | + # use cosmo's internal api to load the errno names 591 | + open(my $cfile, '>', 'errno.c') or 592 | + die("Failed to open errno.c"); 593 | + print $cfile <<'MAGNUM'; 594 | +#include "libc/fmt/magnumstrs.internal.h" 595 | +#include 596 | +int main(void) 597 | +{ 598 | + for (unsigned i = 0; kErrnoNames[i].x != MAGNUM_TERMINATOR; ++i) 599 | + { 600 | + printf("%s\n", MAGNUM_STRING(kErrnoNames, i)); 601 | + } 602 | +} 603 | +MAGNUM 604 | + close($cfile); 605 | + system("$Config{cc} $Config{ccflags} errno.c $Config{ldflags} $Config{libs} -o errno") == 0 or die "Failed to compile errno.c"; 606 | + unlink('errno.c'); 607 | + open(my $errnoout, '-|', './errno') or die "Failed to run errno"; 608 | + while(<$errnoout>) { 609 | + chomp; 610 | + $err{$_} = 1; 611 | + } 612 | + close($errnoout); 613 | + unlink('errno'); 614 | + $err{EWOULDBLOCK} = 1; # EWOULDBLOCK isn't in the table as it's the same value as EAGAIN 615 | +} 616 | else { 617 | foreach $file (@files) { 618 | process_file($file); 619 | @@ -212,12 +239,30 @@ sub write_errno_pm { 620 | if ($IsMSWin32) { 621 | print CPPI qq[#include "../../win32/include/sys/errno2.h"\n]; 622 | } 623 | - 624 | - foreach $err (keys %err) { 625 | - print CPPI '"',$err,'" [[',$err,']]',"\n"; 626 | - } 627 | 628 | - close(CPPI); 629 | + if($^O ne 'cosmo') { 630 | + foreach $err (keys %err) { 631 | + print CPPI '"',$err,'" [[',$err,']]',"\n"; 632 | + } 633 | + close(CPPI); 634 | + } 635 | + else { 636 | + # in cosmo the preprocessor alone isn't enough to determine errno values 637 | + # instead generate and run an executable to generate the file to be fed to the preprocessor 638 | + close(CPPI); 639 | + open(my $CIN, '>', 'errno.c') or 640 | + die "Cannot open errno.c"; 641 | + print $CIN "#include \n#include \n"; 642 | + print $CIN "int main(void){\n"; 643 | + foreach my $name (keys %err) { 644 | + print $CIN ' printf("\\"'.$name.'\\" [[%d]]\n", '."$name);\n"; 645 | + } 646 | + print $CIN "}\n"; 647 | + close($CIN); 648 | + system("$Config{cc} $Config{ccflags} errno.c $Config{ldflags} $Config{libs} -o errno") == 0 or die "Failed to compile errno.c"; 649 | + system("./errno > errno.c") == 0 or die "Failed to generate errno.c"; 650 | + unlink('errno'); 651 | + } 652 | 653 | { # BeOS (support now removed) did not enter this block 654 | # invoke CPP and read the output 655 | @@ -314,9 +359,39 @@ EDQ 656 | foreach $err (@err) { 657 | print "\t$err => $err{$err},\n"; 658 | } 659 | + print " );\n"; 660 | + if($^O eq 'cosmo') { 661 | + open(my $uname, '-|', 'uname') or 662 | + die "Failed to run uname"; 663 | + my $buildos = <$uname>; 664 | + chomp $buildos; 665 | + close($uname); 666 | + print "\n".' my $buildos = '."'$buildos';\n"; 667 | +print <<'ESQ'; 668 | + # In cosmo the constants of errno change based on the current operating 669 | + # system. An XS module is provided to load them, however for miniperl's 670 | + # sake, the constants of the build os are encoded above. 671 | + if(eval "use ErrnoRuntime; 1;") { 672 | + foreach my $key (keys %err) { 673 | + $err{$key} = ErrnoRuntime::strtoerrno($key); 674 | + } 675 | + } 676 | + else { 677 | + open(my $uname, '-|', 'uname') or 678 | + die "Failed to run uname"; 679 | + my $curos = <$uname>; 680 | + close($uname); 681 | + chomp $curos; 682 | + my $failmsg = "The errno constants in Errno.pm are for miniperl on $buildos only"; 683 | + $curos eq $buildos or die $failmsg; 684 | + eval "use Config::Perl::V; 1;" or die "Failed to load Config::Perl::V"; 685 | + my $local_config = Config::Perl::V::myconfig(); 686 | + $local_config->{build}{options}{PERL_IS_MINIPERL} or die $failmsg; 687 | + } 688 | 689 | +ESQ 690 | + } 691 | print <<'ESQ'; 692 | - ); 693 | # Generate proxy constant subroutines for all the values. 694 | # Well, almost all the values. Unfortunately we can't assume that at this 695 | # point that our symbol table is empty, as code such as if the parser has 696 | diff --git a/ext/ErrnoRuntime/.gitignore b/ext/ErrnoRuntime/.gitignore 697 | new file mode 100644 698 | index 0000000000..e54624d60d 699 | --- /dev/null 700 | +++ b/ext/ErrnoRuntime/.gitignore 701 | @@ -0,0 +1 @@ 702 | +!/Makefile.PL 703 | diff --git a/ext/ErrnoRuntime/ErrnoRuntime.xs b/ext/ErrnoRuntime/ErrnoRuntime.xs 704 | new file mode 100644 705 | index 0000000000..598a8a1452 706 | --- /dev/null 707 | +++ b/ext/ErrnoRuntime/ErrnoRuntime.xs 708 | @@ -0,0 +1,34 @@ 709 | +#define PERL_NO_GET_CONTEXT 710 | +#include "EXTERN.h" 711 | +#include "perl.h" 712 | +#include "XSUB.h" 713 | +#include 714 | +#include "libc/fmt/magnumstrs.internal.h" 715 | + 716 | +MODULE = ErrnoRuntime PACKAGE = ErrnoRuntime 717 | + 718 | +IV 719 | +strtoerrno(name) 720 | + const char *name 721 | + CODE: 722 | + unsigned i; 723 | + RETVAL = 0; 724 | + for (i = 0; kErrnoNames[i].x != MAGNUM_TERMINATOR; ++i) 725 | + { 726 | + if(strcmp(name, MAGNUM_STRING(kErrnoNames, i)) == 0) 727 | + { 728 | + RETVAL = MAGNUM_NUMBER(kErrnoNames, i); 729 | + break; 730 | + } 731 | + } 732 | + // EWOULDBLOCK isn't in the table as it's the same as EAGAIN 733 | + if(strcmp(name, "EWOULDBLOCK") == 0) 734 | + { 735 | + RETVAL = EWOULDBLOCK; 736 | + } 737 | + else if(kErrnoNames[i].x == MAGNUM_TERMINATOR) 738 | + { 739 | + croak("Unknown Errno constant %s", name); 740 | + } 741 | + OUTPUT: 742 | + RETVAL 743 | \ No newline at end of file 744 | diff --git a/ext/ErrnoRuntime/Makefile.PL b/ext/ErrnoRuntime/Makefile.PL 745 | new file mode 100644 746 | index 0000000000..799e4a12bf 747 | --- /dev/null 748 | +++ b/ext/ErrnoRuntime/Makefile.PL 749 | @@ -0,0 +1,15 @@ 750 | +BEGIN { require 5.008_001 } 751 | +use ExtUtils::MakeMaker; 752 | + 753 | +# this module only needed and implemented for cosmo right now 754 | +$^O eq 'cosmo' or die "OS unsupported"; 755 | + 756 | +WriteMakefile( 757 | + VERSION_FROM => "lib/ErrnoRuntime.pm", 758 | + NAME => "ErrnoRuntime", 759 | + OBJECT => '$(O_FILES)', 760 | + ABSTRACT => 'Load Errno constants at runtime', 761 | + AUTHOR => 'Gavin Hayes ', 762 | + PREREQ_PM => { 763 | + }, 764 | +); 765 | diff --git a/ext/ErrnoRuntime/lib/ErrnoRuntime.pm b/ext/ErrnoRuntime/lib/ErrnoRuntime.pm 766 | new file mode 100644 767 | index 0000000000..f53859e5d3 768 | --- /dev/null 769 | +++ b/ext/ErrnoRuntime/lib/ErrnoRuntime.pm 770 | @@ -0,0 +1,68 @@ 771 | +package ErrnoRuntime; 772 | + 773 | +use 5.020002; 774 | +use strict; 775 | +use warnings; 776 | +our $VERSION = '0.0'; 777 | + 778 | +require Exporter; 779 | + 780 | +our @ISA = qw(Exporter); 781 | + 782 | +# Items to export into callers namespace by default. Note: do not export 783 | +# names by default without a very good reason. Use EXPORT_OK instead. 784 | +# Do not simply export all your public functions/methods/constants. 785 | + 786 | +# This allows declaration use ErrnoRuntime ':all'; 787 | +# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK 788 | +# will save memory. 789 | +our %EXPORT_TAGS = ( 'all' => [ qw( 790 | + 791 | +) ] ); 792 | + 793 | +our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); 794 | + 795 | +our @EXPORT = qw( 796 | + 797 | +); 798 | + 799 | +require XSLoader; 800 | +XSLoader::load('ErrnoRuntime', $VERSION); 801 | + 802 | +# Preloaded methods go here. 803 | + 804 | +1; 805 | + 806 | +__END__ 807 | + 808 | +=pod 809 | + 810 | +=encoding utf-8 811 | + 812 | +=head1 NAME 813 | + 814 | +ErrnoRuntime - XS extension module for loading errno values at 815 | +runtime 816 | + 817 | +=head1 SYNOPSIS 818 | + 819 | + use ErrnoRuntime; 820 | + 821 | +=head1 AUTHOR 822 | + 823 | +Gavin Hayes, C<< >> 824 | + 825 | +=head1 SUPPORT AND DOCUMENTATION 826 | + 827 | +You can find documentation for this module with the perldoc command. 828 | + 829 | + perldoc ErrnoRuntime 830 | + 831 | +=head1 LICENSE AND COPYRIGHT 832 | + 833 | +This software is copyright (c) 2022 by Gavin Hayes. 834 | + 835 | +This is free software; you can redistribute it and/or modify it under 836 | +the same terms as the Perl 5 programming language system itself. 837 | + 838 | +=cut 839 | diff --git a/ext/POSIX/t/sigaction.t b/ext/POSIX/t/sigaction.t 840 | index 024c66a147..2741c895ed 100644 841 | --- a/ext/POSIX/t/sigaction.t 842 | +++ b/ext/POSIX/t/sigaction.t 843 | @@ -51,7 +51,7 @@ ok($oldaction->{MASK}->ismember(SIGUSR1), "SIGUSR1 ismember MASK"); 844 | 845 | SKIP: { 846 | skip("sigaction() thinks different in $^O", 1) 847 | - if $^O eq 'linux' || $^O eq 'unicos'; 848 | + if $^O eq 'linux' || $^O eq 'unicos' || $^O eq 'cosmo'; 849 | is($oldaction->{FLAGS}, 0); 850 | } 851 | 852 | diff --git a/hints/cosmo.sh b/hints/cosmo.sh 853 | new file mode 100644 854 | index 0000000000..3d7118a4f9 855 | --- /dev/null 856 | +++ b/hints/cosmo.sh 857 | @@ -0,0 +1,21 @@ 858 | +#! /bin/sh 859 | +# cosmo.sh - hints for building perl using the Cosmopolitan Libc 860 | +# 861 | + 862 | +test -d "$COSMOCC" || exit 1; 863 | + 864 | +usedl='undef' 865 | +usenm='false' 866 | +so='none' 867 | +osname='cosmo' 868 | +osvers='' 869 | +libpth='' 870 | +d_procselfexe='undef' 871 | +locincpth='' 872 | +loclibpth='' 873 | +glibpth='' 874 | +cc="$COSMOCC/bin/x86_64-unknown-cosmo-cc" 875 | +ccflags="-fno-stack-protector -D_COSMO_SOURCE" 876 | +ldflags="-fno-stack-protector" 877 | +libs='' 878 | +unset COSMOCC 879 | diff --git a/lib/.gitignore b/lib/.gitignore 880 | index cb6a26cfcc..8d99235088 100644 881 | --- a/lib/.gitignore 882 | +++ b/lib/.gitignore 883 | @@ -37,6 +37,7 @@ 884 | /Encode/ 885 | /Env.pm 886 | /Errno.pm 887 | +/ErrnoRuntime.pm 888 | /Exporter.pm 889 | /Exporter/ 890 | /ExtUtils/CBuilder.pm 891 | diff --git a/patchlevel.h b/patchlevel.h 892 | index 52a8d53879..d52e867594 100644 893 | --- a/patchlevel.h 894 | +++ b/patchlevel.h 895 | @@ -157,6 +157,13 @@ hunk. 896 | # endif 897 | static const char * const local_patches[] = { 898 | NULL 899 | + ,"G4Vi:cosmo/c473e9-73ecc6c - https://github.com/G4Vi/perl5/compare/c473e9~1...73ecc6c various changes to support building with the Cosmopolitan Libc" 900 | + ,"G4Vi:cosmo/2fb034f - https://github.com/G4Vi/perl5/commit/2fb034ffb02db2b3ac09706c954704930c620c0b fix Time-HiRes Configure to work for cosmopolitan" 901 | + ,"G4Vi:cosmo/3643b8b - https://github.com/G4Vi/perl5/commit/3643b8bd369ea1e8715a27ce8821c8e70f2c17e0 add cosmo as Unix in Perl::OSType (fixes Module::Build)" 902 | + ,"G4Vi:cosmo/e3d8537 - https://github.com/G4Vi/perl5/commit/e3d853703f5c7c951a14e1eed186105cc0e0b7e3 s/perl.elf$/perl.com.dbg/ as perl.com.dbg is useful for --ftrace" 903 | + ,"G4Vi:cosmo/7138814 - https://github.com/G4Vi/perl5/commit/713881482f9968f4960090d2699bc4cb4a46dc94 update for cosmo 3.0.2, new ape copying" 904 | + ,"G4Vi:cosmo/ecf4f8d - https://github.com/G4Vi/perl5/commit/ecf4f8ddb6aaad4544b8e16541c52b4dc570b491 revert a no longer needed switch rewrite" 905 | + ,"G4Vi:cosmo/022d57c - https://github.com/G4Vi/perl5/commit/022d57c45c0005ea8a1d9a5b8fe7eb7eb7b29225 revert ecf4f8d and 7138814" 906 | #ifdef PERL_GIT_UNCOMMITTED_CHANGES 907 | ,"uncommitted-changes" 908 | #endif 909 | diff --git a/pod/.gitignore b/pod/.gitignore 910 | index a16aaa9a5f..b731fa2fd6 100644 911 | --- a/pod/.gitignore 912 | +++ b/pod/.gitignore 913 | @@ -4,6 +4,7 @@ 914 | /perlandroid.pod 915 | /perlbs2000.pod 916 | /perlcn.pod 917 | +/perlcosmo.pod 918 | /perlcygwin.pod 919 | /perldos.pod 920 | /perlfreebsd.pod 921 | diff --git a/pod/perl.pod b/pod/perl.pod 922 | index 6a14569758..5db5882a9c 100644 923 | --- a/pod/perl.pod 924 | +++ b/pod/perl.pod 925 | @@ -277,6 +277,7 @@ aux h2ph h2xs perlbug pl2pm pod2html pod2man splain xsubpp 926 | perlamiga Perl notes for AmigaOS 927 | perlandroid Perl notes for Android 928 | perlbs2000 Perl notes for POSIX-BC BS2000 929 | + perlcosmo Perl notes for the Cosmopolitan Libc 930 | perlcygwin Perl notes for Cygwin 931 | perlfreebsd Perl notes for FreeBSD 932 | perlhaiku Perl notes for Haiku 933 | diff --git a/t/op/magic.t b/t/op/magic.t 934 | index 2004a5055c..a33548c71f 100644 935 | --- a/t/op/magic.t 936 | +++ b/t/op/magic.t 937 | @@ -276,7 +276,7 @@ $$ = $pid; # Tests below use $$ 938 | # $^X and $0 939 | { 940 | my $is_abs = $Config{d_procselfexe} || $Config{usekernprocpathname} 941 | - || $Config{usensgetexecutablepath}; 942 | + || $Config{usensgetexecutablepath} || ($^O eq 'cosmo'); 943 | if ($^O eq 'qnx') { 944 | chomp($wd = `/usr/bin/fullpath -t`); 945 | } 946 | -------------------------------------------------------------------------------- /t/tests.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | use Test::More; 5 | use Cwd qw(abs_path); 6 | # Perl::Dist::APPerl currently loads apperl-project.json from the current directory, so hack the cwd 7 | BEGIN { 8 | $0 = abs_path($0); 9 | foreach my $inc (@INC) { 10 | $inc = abs_path($inc); 11 | } 12 | mkdir('tests_temp'); 13 | chdir('tests_temp'); 14 | { 15 | open(my $fh, '>', 'apperl-project.json') or die "unable to write apperl-project.json"; 16 | print $fh '{"defaultconfig":"hello","apperl_configs":{"hello":{"dest":"hello.com","base":"nobuild-v0.1.0","default_script":"/zip/bin/hello","zip_extra_files":{"bin":["src/hello"]}}}}'; 17 | close($fh); 18 | } 19 | } 20 | use Perl::Dist::APPerl; 21 | use File::Copy "cp"; 22 | my @apperlconfigs = qw(hello); 23 | if(! -e 'src/perl.com') { 24 | if(! -e '../perl.com') { 25 | plan skip_all => 'Cannot build without perl.com'; 26 | } 27 | mkdir('src'); 28 | cp('../perl.com', 'src/perl.com'); 29 | my $perm = (stat('src/perl.com'))[2] & 07777; 30 | chmod($perm | 0111, 'src/perl.com'); 31 | } 32 | 33 | plan tests => 2 * scalar(@apperlconfigs); 34 | 35 | open(my $hh, '>', 'src/hello') or die "unable to write src/hello"; 36 | print $hh <<'HELLO'; 37 | print "hello\n"; 38 | HELLO 39 | close($hh); 40 | 41 | foreach my $config (@apperlconfigs) { 42 | while(1) { 43 | my $ret = hide_out_and_err(sub { Perl::Dist::APPerl::apperlm('checkout', $config); }); 44 | ok($ret, "apperlm checkout $config"); 45 | $ret or last; 46 | $ret = hide_out_and_err(sub { Perl::Dist::APPerl::apperlm('build'); }); 47 | ok($ret, "apperlm build ($config)"); 48 | last; 49 | } 50 | } 51 | 52 | sub hide_out_and_err { 53 | my ($callback) = @_; 54 | open(my $saved_stderr, '>&', STDERR) or die "$!"; 55 | open(my $saved_stdout, '>&', STDOUT) or die "$!"; 56 | close(STDERR); 57 | close(STDOUT); 58 | open(STDOUT, '>', '/dev/null') or die "$!"; 59 | open(STDERR, '>', '/dev/null') or die "$!"; 60 | my $ret = $callback->(); 61 | close(STDERR); 62 | open(STDERR, '>&', $saved_stderr) or die "$!"; 63 | close(STDOUT); 64 | open(STDOUT, '>&', $saved_stdout) or die "$!"; 65 | return $ret; 66 | } 67 | -------------------------------------------------------------------------------- /xt/author/build.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use strict; 4 | use warnings; 5 | use Test::More; 6 | use Perl::Dist::APPerl; 7 | use File::Copy "cp"; 8 | my @apperlconfigs = qw(full small full-vista small-vista nobuild-v0.1.0); 9 | plan tests => 3 * scalar(@apperlconfigs); 10 | 11 | my %binmapping = ( 12 | full => 'perl.com', 13 | small => 'perl-small.com', 14 | 'full-vista' => 'perl-vista.com', 15 | 'small-vista' => 'perl-small-vista.com', 16 | 'nobuild-v0.1.0' => 'perl-nobuild.com' 17 | ); 18 | 19 | foreach my $config (@apperlconfigs) { 20 | SKIP: { 21 | skip "$config bin already exists", 3 if( -e $binmapping{$config}); 22 | my $isnobuild = $config =~ /nobuild/; 23 | if($isnobuild) { 24 | mkdir('src'); 25 | cp('perl.com', 'src/perl.com'); 26 | my $perm = (stat('src/perl.com'))[2] & 07777; 27 | chmod($perm | 0111, 'src/perl.com'); 28 | } 29 | while(1) { 30 | my $ret = hide_out_and_err(sub { Perl::Dist::APPerl::apperlm('checkout', $config); }); 31 | ok($ret, "apperlm checkout $config"); 32 | $ret or last; 33 | SKIP: { 34 | skip "nobuild configs do not configure", 1 if($isnobuild ); 35 | $ret = hide_out_and_err(sub { Perl::Dist::APPerl::apperlm('configure'); }); 36 | ok($ret, "apperlm configure ($config)"); 37 | $ret or last; 38 | } 39 | $ret = hide_out_and_err(sub { Perl::Dist::APPerl::apperlm('build'); }); 40 | ok($ret, "apperlm build ($config)"); 41 | last; 42 | } 43 | } 44 | } 45 | 46 | sub hide_out_and_err { 47 | my ($callback) = @_; 48 | open(my $saved_stderr, '>&', STDERR) or die "$!"; 49 | open(my $saved_stdout, '>&', STDOUT) or die "$!"; 50 | close(STDERR); 51 | close(STDOUT); 52 | open(STDOUT, '>', '/dev/null') or die "$!"; 53 | open(STDERR, '>', '/dev/null') or die "$!"; 54 | my $ret = $callback->(); 55 | close(STDERR); 56 | open(STDERR, '>&', $saved_stderr) or die "$!"; 57 | close(STDOUT); 58 | open(STDOUT, '>&', $saved_stdout) or die "$!"; 59 | return $ret; 60 | } 61 | -------------------------------------------------------------------------------- /xt/author/pod_linkcheck.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use strict; 4 | use warnings; 5 | use Test::More; 6 | use Test::Pod::LinkCheck::Lite; 7 | 8 | Test::Pod::LinkCheck::Lite->new->all_pod_files_ok('.'); 9 | done_testing(); 10 | --------------------------------------------------------------------------------