mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-10 10:25:36 +08:00
Compare commits
1 Commits
d31e1b00e8
...
pure-shell
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5ee452499 |
21
.gitignore
vendored
21
.gitignore
vendored
@@ -1,21 +0,0 @@
|
|||||||
.idea
|
|
||||||
runtime/
|
|
||||||
docker/libraries/
|
|
||||||
docker/extensions/
|
|
||||||
docker/source/
|
|
||||||
|
|
||||||
# Composer file
|
|
||||||
composer.lock
|
|
||||||
/vendor/
|
|
||||||
|
|
||||||
# default source extract directory
|
|
||||||
/source/
|
|
||||||
|
|
||||||
# default source download directory
|
|
||||||
/downloads/
|
|
||||||
|
|
||||||
# default source build root directory
|
|
||||||
/buildroot/
|
|
||||||
|
|
||||||
# php cs fixer cache file
|
|
||||||
.php-cs-fixer.cache
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
return (new PhpCsFixer\Config())
|
|
||||||
->setRiskyAllowed(true)
|
|
||||||
->setRules([
|
|
||||||
'@PSR12' => true,
|
|
||||||
'@Symfony' => true,
|
|
||||||
'@PhpCsFixer' => true,
|
|
||||||
'array_syntax' => [
|
|
||||||
'syntax' => 'short',
|
|
||||||
],
|
|
||||||
'list_syntax' => [
|
|
||||||
'syntax' => 'short',
|
|
||||||
],
|
|
||||||
'concat_space' => [
|
|
||||||
'spacing' => 'one',
|
|
||||||
],
|
|
||||||
'blank_line_before_statement' => [
|
|
||||||
'statements' => [
|
|
||||||
'declare',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'ordered_imports' => [
|
|
||||||
'imports_order' => [
|
|
||||||
'class',
|
|
||||||
'function',
|
|
||||||
'const',
|
|
||||||
],
|
|
||||||
'sort_algorithm' => 'alpha',
|
|
||||||
],
|
|
||||||
'single_line_comment_style' => [
|
|
||||||
'comment_types' => [
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'yoda_style' => [
|
|
||||||
'always_move_variable' => false,
|
|
||||||
'equal' => false,
|
|
||||||
'identical' => false,
|
|
||||||
],
|
|
||||||
'multiline_whitespace_before_semicolons' => [
|
|
||||||
'strategy' => 'no_multi_line',
|
|
||||||
],
|
|
||||||
'constant_case' => [
|
|
||||||
'case' => 'lower',
|
|
||||||
],
|
|
||||||
'class_attributes_separation' => true,
|
|
||||||
'combine_consecutive_unsets' => true,
|
|
||||||
'declare_strict_types' => true,
|
|
||||||
'linebreak_after_opening_tag' => true,
|
|
||||||
'lowercase_static_reference' => true,
|
|
||||||
'no_useless_else' => true,
|
|
||||||
'no_unused_imports' => true,
|
|
||||||
'not_operator_with_successor_space' => false,
|
|
||||||
'not_operator_with_space' => false,
|
|
||||||
'ordered_class_elements' => true,
|
|
||||||
'php_unit_strict' => false,
|
|
||||||
'phpdoc_separation' => false,
|
|
||||||
'single_quote' => true,
|
|
||||||
'standardize_not_equals' => true,
|
|
||||||
'multiline_comment_opening_closing' => true,
|
|
||||||
'phpdoc_summary' => false,
|
|
||||||
'php_unit_test_class_requires_covers' => false,
|
|
||||||
'phpdoc_var_without_name' => false,
|
|
||||||
])
|
|
||||||
->setFinder(
|
|
||||||
PhpCsFixer\Finder::create()->in(__DIR__ . '/src')
|
|
||||||
);
|
|
||||||
687
LICENSE
687
LICENSE
@@ -1,21 +1,674 @@
|
|||||||
MIT License
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
Copyright (c) 2022-2023 Jerry Ma
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Preamble
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
The GNU General Public License is a free, copyleft license for
|
||||||
copies or substantial portions of the Software.
|
software and other kinds of works.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
The licenses for most software and other practical works are designed
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
to take away your freedom to share and change the works. By contrast,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
share and change all versions of a program--to make sure it remains free
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
GNU General Public License for most of our software; it applies also to
|
||||||
SOFTWARE.
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||||
|
|||||||
169
README-en.md
Executable file → Normal file
169
README-en.md
Executable file → Normal file
@@ -1,121 +1,74 @@
|
|||||||
# static-php-cli
|
# static-php-swoole
|
||||||
|
Compile A Statically Linked PHP With Swoole and other Extensions. [English README](/README-en.md)
|
||||||
|
|
||||||
Compile A Statically Linked PHP With Swoole and other Extensions.
|
BTW, It's only for CLI mode.
|
||||||
|
|
||||||
Compile a purely static PHP binary file with various extensions to make PHP-cli applications more portable!
|
[]()
|
||||||
|
|
||||||
You can also use the micro binary file to package PHP source code and binary files into one for distribution!
|
## Requirements
|
||||||
|
- Tested on `x86_64` and `aarch64` platform, others have not tested.
|
||||||
|
- Requiring Alpine Linux (version >= 3.13), or requiring musl-libc
|
||||||
|
- Support WSL2
|
||||||
|
- Supporting PHP version >= 7.3
|
||||||
|
|
||||||
Note: only support cli SAPI, not support fpm, cgi.
|
## Start
|
||||||
|
You can directly download static binary in Release.
|
||||||
## Compilation Requirements
|
|
||||||
|
|
||||||
Yes, this project is written in PHP, pretty funny.
|
|
||||||
But php-static-cli only requires an environment above PHP 8.0.
|
|
||||||
|
|
||||||
- Linux
|
|
||||||
- Supported arch: aarch64, amd64
|
|
||||||
- Supported distributions: alpine, ubuntu, centos
|
|
||||||
- Requirements: make, bison, flex, pkg-config, git, autoconf, automake, tar, unzip, gzip, bzip2, cmake
|
|
||||||
- macOS
|
|
||||||
- Supported arch: arm64, x86_64
|
|
||||||
- Requirements: make, bison, flex, pkg-config, git, autoconf, automake, tar, unzip, xz, gzip, bzip2, cmake
|
|
||||||
- Windows
|
|
||||||
- Supported arch: x86_64
|
|
||||||
- Requirements: (TODO)
|
|
||||||
- PHP
|
|
||||||
- Supported version: 7.4, 8.0, 8.1, 8.2
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
After stable release for this project, a single phar and single binary for this tool will be published.
|
|
||||||
|
|
||||||
And currently you may need to clone this branch and edit GitHub Action to build.
|
|
||||||
|
|
||||||
### Compilation
|
|
||||||
|
|
||||||
|
Here's help command to compile it yourself:
|
||||||
```bash
|
```bash
|
||||||
chmod +x spc
|
# Compile script
|
||||||
# fetch all libraries
|
./static-compile-php.sh
|
||||||
./spc fetch --all
|
# And now you get `php-dist/bin/php` file!
|
||||||
# with bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl extension, build both CLI and phpmicro SAPI
|
|
||||||
./spc build bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl --build-all
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### php-cli Usage
|
## Library version
|
||||||
|
- php: 7.4.18
|
||||||
|
- libxml2: 2.9.10
|
||||||
|
- curl: 7.76.1
|
||||||
|
|
||||||
When using the parameter `--build-all` or not adding the `--build-micro` parameter,
|
## Including PHP extensions
|
||||||
the final compilation result will output a binary file named `./php`,
|
- bcmath
|
||||||
which can be distributed and used directly.
|
- calendar
|
||||||
This file will be located in the directory `source/php-src/sapi/cli/`, simply copy it out for use.
|
- ctype
|
||||||
|
- filter
|
||||||
|
- openssl
|
||||||
|
- pcntl
|
||||||
|
- iconv
|
||||||
|
- inotify (3.0.0)
|
||||||
|
- json
|
||||||
|
- mbstring
|
||||||
|
- phar
|
||||||
|
- curl
|
||||||
|
- pdo
|
||||||
|
- gd
|
||||||
|
- pdo_mysql
|
||||||
|
- mysqlnd
|
||||||
|
- sockets
|
||||||
|
- swoole (4.6.6)
|
||||||
|
- redis (5.3.4)
|
||||||
|
- simplexml
|
||||||
|
- dom
|
||||||
|
- xml
|
||||||
|
- xmlwriter
|
||||||
|
- xmlreader
|
||||||
|
- posix
|
||||||
|
- tokenizer
|
||||||
|
|
||||||
```bash
|
## Running preview
|
||||||
./php -v
|
After-compile status
|
||||||
./php -m
|

|
||||||
./php your_code.php
|
|
||||||
```
|
|
||||||
|
|
||||||
### micro.sfx Usage
|
Run Swoft framework directly
|
||||||
|

|
||||||
|
|
||||||
When using the parameter `--build-all` or `--build-micro`,
|
## Todo List
|
||||||
the final compilation result will output a file named `./micro.sfx`,
|
- [X] curl/libcurl extension support
|
||||||
which needs to be used with your PHP source code like `code.php`.
|
- [ ] Alternative extension compiling
|
||||||
This file will be located in the directory `source/php-src/sapi/micro/`, simply copy it out for use.
|
- [ ] php.ini support
|
||||||
|
- [ ] Make composer together
|
||||||
|
- [ ] i18n
|
||||||
|
|
||||||
Prepare your project source code, which can be a single PHP file or a Phar file, for use.
|
## References
|
||||||
|
- <https://blog.terrywh.net/post/2019/php-static-openssl/>
|
||||||
```bash
|
- <https://stackoverflow.com/a/37245653>
|
||||||
echo "<?php echo 'Hello world' . PHP_EOL;" > code.php
|
- <http://blog.gaoyuan.xyz/2014/04/09/statically-compile-php/>
|
||||||
cat micro.sfx code.php > single-app && chmod +x single-app
|
|
||||||
./single-app
|
|
||||||
|
|
||||||
# If packing a PHAR file, simply replace code.php with the Phar file path.
|
|
||||||
```
|
|
||||||
|
|
||||||
> In some cases, PHAR files may not run in a micro environment.
|
|
||||||
|
|
||||||
## Current Status
|
|
||||||
|
|
||||||
- [X] Basic CLI framework (by `symfony/console`)
|
|
||||||
- [X] Linux support
|
|
||||||
- [X] macOS support
|
|
||||||
- [X] Exception handler
|
|
||||||
- [ ] Windows support
|
|
||||||
- [X] PHP 7.4 support
|
|
||||||
|
|
||||||
## Supported Extensions
|
|
||||||
|
|
||||||
[Support Extension List](/ext-support.md)
|
|
||||||
|
|
||||||
## Contribution
|
|
||||||
|
|
||||||
Currently, there are only a few supported extensions.
|
|
||||||
If the extension you need is missing, you can create an issue.
|
|
||||||
If you are familiar with this project, you are also welcome to initiate a pull request.
|
|
||||||
|
|
||||||
The basic principles for contributing are as follows:
|
|
||||||
|
|
||||||
- This project uses php-cs-fixer and phpstan as code formatting tools. Before contributing, please run `composer analyze` and `composer cs-fix` on the updated code.
|
|
||||||
- If other open source libraries are involved, the corresponding licenses should be provided.
|
|
||||||
Also, configuration files should be sorted using the command `sort-config` after modification.
|
|
||||||
For more information about sorting commands, see the documentation.
|
|
||||||
- Naming conventions should be followed, such as using the extension name registered in PHP for the extension name itself,
|
|
||||||
and external library names should follow the project's own naming conventions. For internal logic functions, class names, variables, etc.,
|
|
||||||
camelCase and underscore formats should be followed, and mixing within the same module is prohibited.
|
|
||||||
- When compiling external libraries and creating patches, compatibility with different operating systems should be considered.
|
|
||||||
|
|
||||||
## Open-Source License
|
|
||||||
|
|
||||||
This project is based on the tradition of using the MIT License for old versions,
|
|
||||||
while the new version references source code from some other projects.
|
|
||||||
Special thanks to:
|
|
||||||
|
|
||||||
- [dixyes/lwmbs](https://github.com/dixyes/lwmbs) (Mulun Permissive License)
|
|
||||||
- [swoole/swoole-cli](https://github.com/swoole/swoole-cli) (Apache 2.0 LICENSE+SWOOLE-CLI LICENSE)
|
|
||||||
|
|
||||||
Due to the special nature of this project,
|
|
||||||
many other open source projects such as curl and protobuf will be used during the project compilation process,
|
|
||||||
and they all have their own open source licenses.
|
|
||||||
|
|
||||||
Please use the `dump-license`(TODO) command to export the open source licenses used in the project after compilation,
|
|
||||||
and comply with the corresponding project's LICENSE.
|
|
||||||
|
|||||||
153
README.md
Executable file → Normal file
153
README.md
Executable file → Normal file
@@ -1,108 +1,87 @@
|
|||||||
# static-php-cli
|
# static-php-cli
|
||||||
|
Compile A Statically Linked PHP With Swoole and other Extensions. [English README](/README-en.md)
|
||||||
Compile A Statically Linked PHP With Swoole and other Extensions. [English README](README-en.md)
|
|
||||||
|
|
||||||
编译纯静态的 PHP Binary 二进制文件,带有各种扩展,让 PHP-cli 应用变得更便携!
|
编译纯静态的 PHP Binary 二进制文件,带有各种扩展,让 PHP-cli 应用变得更便携!
|
||||||
|
|
||||||
同时可以使用 micro 二进制文件,将 PHP 源码和 PHP 二进制构建为一个文件分发!
|
注:只能编译 CLI 模式,暂不支持 CGI 和 FPM 模式
|
||||||
|
|
||||||
注:只能编译 CLI 模式,暂不支持 CGI 和 FPM 模式。
|
**这个分支是旧版本的纯 shell 脚本版本,新版本在 master 分支,换成了 Dockerfile 版本,可以更加便捷地在不同系统下进行构建了!**
|
||||||
|
|
||||||
[]()
|
[]()
|
||||||
|
|
||||||
## 编译环境需求
|
## 环境需求
|
||||||
|
- 目前在 x86_64 和 aarch64(arm64) 架构上编译成功,其他架构需自行测试
|
||||||
|
- 需要 Docker(或等我将脚本提出来也可以直接在 Alpine Linux 上使用)
|
||||||
|
- 脚本支持编译的 PHP 版本(7.2 ~ 8.0)
|
||||||
|
|
||||||
是的,本项目采用 PHP 编写,编译前需要一个 PHP 环境,比较滑稽。
|
## 开始
|
||||||
但本项目默认可通过自身构建的 micro 和 static-php 二进制运行,其他只需要包含 tokenizer 扩展和 PHP 版本大于等于 8.0 即可。
|
可以直接在旁边的 Release 中下载编译好的二进制。
|
||||||
|
|
||||||
- Linux
|
|
||||||
- 支持架构: aarch64, amd64
|
|
||||||
- 支持发行版: alpine, ubuntu, centos
|
|
||||||
- 依赖工具: make, bison, flex, pkg-config, git, autoconf, automake, tar, unzip, gzip, bzip2, cmake
|
|
||||||
- macOS
|
|
||||||
- 支持架构: arm64, x86_64
|
|
||||||
- 依赖工具: make, bison, flex, pkg-config, git, autoconf, automake, tar, unzip, xz, gzip, bzip2, cmake
|
|
||||||
- Windows
|
|
||||||
- 支持架构: x86_64
|
|
||||||
- 依赖工具: (TODO)
|
|
||||||
- PHP
|
|
||||||
- 支持版本: 7.4, 8.0, 8.1, 8.2
|
|
||||||
|
|
||||||
## 使用(WIP)
|
|
||||||
|
|
||||||
> 你正在看的是重构后的 static-php-cli 编译项目,新项目还未完全重构,所以还有大量的扩展没有完成。
|
|
||||||
> 你可以阅读使用 bash 编写的仅为 Linux 系统使用的静态编译脚本和 Docker,详见 bash-version 分支。 旧版本未来将会切换为次要版本,提供有限支持。
|
|
||||||
|
|
||||||
未来会提供一个直接可使用的 phar 包和一个 phpmicro 打包的二进制文件,你可以直接从 Release 中获取并使用:
|
|
||||||
|
|
||||||
### 编译
|
|
||||||
|
|
||||||
|
也可以自己使用 Dockerfile 进行编译构建:
|
||||||
```bash
|
```bash
|
||||||
chmod +x spc
|
git clone https://github.com/crazywhalecc/static-php-cli.git
|
||||||
# 拉取所有依赖库
|
cd static-php-cli/docker
|
||||||
./spc fetch --all
|
docker build -t static-php .
|
||||||
# 构建包含 bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl 扩展的 php-cli 和 micro.sfx
|
|
||||||
./spc build "bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl" --build-all
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 使用 php-cli
|
编译之后可以使用下方命令将二进制 PHP 提取出来,用以下方式:
|
||||||
|
|
||||||
采用参数 `--build-all` 或不添加 `--build-micro` 参数时,最后编译结果会输出一个 `./php` 的二进制文件,此文件可分发、可直接使用。
|
|
||||||
该文件编译后会存放在 `source/php-src/sapi/cli/` 目录中,拷贝出来即可。
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./php -v
|
mkdir dist
|
||||||
./php -m
|
docker run --rm -v $(pwd)/dist:/dist/ -it static cp php-dist/bin/php /dist/
|
||||||
./php your_code.php
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 使用 micro.sfx
|
如果要选择安装的扩展,可以修改 `docker/extensions.txt` 文件,具体规则如下:
|
||||||
|
- 文件内使用 `#` 可以注释,表示不安装
|
||||||
|
- 扩展名一律使用小写,目前默认状态下文件内所列的扩展为支持的扩展,其他扩展暂不支持,如有需求请提 Issue 添加
|
||||||
|
|
||||||
采用项目参数 `--build-all` 或 `--build-micro` 时,最后编译结果会输出一个 `./micro.sfx` 的文件,此文件需要配合你的 PHP 源码使用。
|
## 支持的扩展(对勾为已支持的扩展,未打勾的正在努力兼容)
|
||||||
该文件编译后会存放在 `source/php-src/sapi/micro/` 目录中,拷贝出来即可。
|
- [X] bcmath
|
||||||
|
- [X] calendar
|
||||||
|
- [X] ctype
|
||||||
|
- [X] filter
|
||||||
|
- [X] openssl
|
||||||
|
- [X] pcntl
|
||||||
|
- [X] iconv
|
||||||
|
- [X] inotify
|
||||||
|
- [X] json
|
||||||
|
- [X] mbstring
|
||||||
|
- [X] phar
|
||||||
|
- [X] curl
|
||||||
|
- [X] pdo
|
||||||
|
- [X] gd
|
||||||
|
- [X] pdo_mysql
|
||||||
|
- [X] mysqlnd
|
||||||
|
- [X] sockets
|
||||||
|
- [X] swoole
|
||||||
|
- [X] redis
|
||||||
|
- [X] simplexml
|
||||||
|
- [X] dom
|
||||||
|
- [X] xml
|
||||||
|
- [X] xmlwriter
|
||||||
|
- [X] xmlreader
|
||||||
|
- [X] posix
|
||||||
|
- [X] tokenizer
|
||||||
|
- [ ] zip
|
||||||
|
|
||||||
使用时应准备好你的项目源码文件,可以是单个 PHP 文件,也可以是 Phar 文件。
|
## 目前的问题(待解决的)
|
||||||
|
- [ ] event 扩展的 sockets 支持不能在静态编译中使用,因为静态内嵌编译暂时没办法调整扩展编译顺序。
|
||||||
|
- [ ] Swoole 扩展不支持 `--enable-swoole-curl`,也是因为编译顺序和加载顺序的问题。
|
||||||
|
- [ ] readline 扩展安装后无法正常使用 `php -a`,原因还没有弄清楚,可能是静态编译造成的 ncurses 库出现了问题。
|
||||||
|
|
||||||
```bash
|
## Todo List
|
||||||
echo "<?php echo 'Hello world' . PHP_EOL;" > code.php
|
- [X] curl/libcurl 扩展静态编译
|
||||||
cat micro.sfx code.php > single-app && chmod +x single-app
|
- [X] 可自行选择不需要编译进入的扩展
|
||||||
./single-app
|
- [ ] php.ini 内嵌或分发
|
||||||
|
- [ ] i18n(国际化脚本本身和 README)
|
||||||
|
|
||||||
# 如果打包 PHAR 文件,仅需把 code.php 更换为 phar 文件路径即可
|
## 运行示例
|
||||||
```
|
编译后的状态
|
||||||
|

|
||||||
|
|
||||||
> 有些情况下的 phar 文件可能无法在 micro 环境下运行。
|
在不同系统直接运行 Swoft
|
||||||
|

|
||||||
|
|
||||||
## 项目支持情况
|
## 参考资料
|
||||||
|
- <https://blog.terrywh.net/post/2019/php-static-openssl/>
|
||||||
- [X] 基础结构编写(采用 `symfony/console`)
|
- <https://stackoverflow.com/a/37245653>
|
||||||
- [X] 错误处理
|
- <http://blog.gaoyuan.xyz/2014/04/09/statically-compile-php/>
|
||||||
- [X] macOS 支持
|
|
||||||
- [ ] Windows 支持
|
|
||||||
- [X] Linux 支持
|
|
||||||
- [X] PHP 7.4 支持
|
|
||||||
|
|
||||||
## 支持的扩展情况
|
|
||||||
|
|
||||||
[扩展支持列表](/ext-support.md)
|
|
||||||
|
|
||||||
## 贡献
|
|
||||||
|
|
||||||
目前支持的扩展较少,如果缺少你需要的扩展,可发起 Issue。如果你对本项目较熟悉,也欢迎为本项目发起 Pull Request。
|
|
||||||
|
|
||||||
贡献基本原则如下:
|
|
||||||
|
|
||||||
- 项目采用了 php-cs-fixer、phpstan 作为代码规范工具,贡献前请对更新的代码执行 `composer analyze` 和 `composer cs-fix`。
|
|
||||||
- 涉及到其他开源库的部分应提供对应库的协议,同时对配置文件在修改后采用命令 `sort-config` 排序。有关排序的命令,见文档。
|
|
||||||
- 应遵循命名规范,例如扩展名称应采取 PHP 内注册的扩展名本身,外部库名应遵循项目本身的名称,内部逻辑的函数、类名、变量等应遵循驼峰、下划线等格式,禁止同一模块混用。
|
|
||||||
- 涉及编译外部库的命令和 Patch 时应注意兼容不同操作系统。
|
|
||||||
|
|
||||||
## 开源协议
|
|
||||||
|
|
||||||
本项目依据旧版本惯例采用 MIT License 开源,新版本采用了部分项目的源代码做参考,特别感谢:
|
|
||||||
|
|
||||||
- [dixyes/lwmbs](https://github.com/dixyes/lwmbs)(木兰宽松许可证)
|
|
||||||
- [swoole/swoole-cli](https://github.com/swoole/swoole-cli)(Apache 2.0 LICENSE+SWOOLE-CLI LICENSE)
|
|
||||||
|
|
||||||
因本项目的特殊性,使用项目编译过程中会使用很多其他开源项目,例如 curl、protobuf 等,它们都有各自的开源协议。
|
|
||||||
请在编译完成后,使用命令 `dump-license`(TODO) 导出项目使用项目的开源协议,并遵守对应项目的 LICENSE。
|
|
||||||
|
|||||||
16
bin/spc
16
bin/spc
@@ -1,16 +0,0 @@
|
|||||||
#!php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once __DIR__ . '/../vendor/autoload.php';
|
|
||||||
|
|
||||||
// 防止 Micro 打包状态下不支持中文的显示(虽然这个项目目前好像没输出过中文?)
|
|
||||||
if (PHP_OS_FAMILY === 'Windows' && Phar::running()) {
|
|
||||||
exec('CHCP 65001');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 跑,反正一条命令跑就对了
|
|
||||||
try {
|
|
||||||
(new \SPC\ConsoleApplication())->run();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
\SPC\exception\ExceptionHandler::getInstance()->handle($e);
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
{
|
|
||||||
"pre-push": {
|
|
||||||
"enabled": true,
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"action": "composer analyse"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"pre-commit": {
|
|
||||||
"enabled": true,
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"action": "composer cs-fix -- --config=.php-cs-fixer.php --dry-run --diff {$STAGED_FILES|of-type:php}",
|
|
||||||
"conditions": [
|
|
||||||
{
|
|
||||||
"exec": "\\CaptainHook\\App\\Hook\\Condition\\FileStaged\\OfType",
|
|
||||||
"args": ["php"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"post-change": {
|
|
||||||
"enabled": true,
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"action": "composer install",
|
|
||||||
"options": [],
|
|
||||||
"conditions": [
|
|
||||||
{
|
|
||||||
"exec": "\\CaptainHook\\App\\Hook\\Condition\\FileChanged\\Any",
|
|
||||||
"args": [
|
|
||||||
[
|
|
||||||
"composer.json",
|
|
||||||
"composer.lock"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "crazywhalecc/static-php-cli",
|
|
||||||
"description": "Build single static PHP binary, with PHP project together, with popular extensions included.",
|
|
||||||
"license": "MIT",
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "jerry",
|
|
||||||
"email": "admin@zhamao.me"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"require": {
|
|
||||||
"php": ">= 8.0",
|
|
||||||
"ext-tokenizer": "*",
|
|
||||||
"ext-iconv": "*",
|
|
||||||
"symfony/console": "^6 || ^5 || ^4",
|
|
||||||
"zhamao/logger": "^1.0",
|
|
||||||
"crazywhalecc/cli-helper": "^0.1.0",
|
|
||||||
"nunomaduro/collision": "*"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"friendsofphp/php-cs-fixer": "^3.2 != 3.7.0",
|
|
||||||
"phpstan/phpstan": "^1.1",
|
|
||||||
"captainhook/captainhook": "^5.10",
|
|
||||||
"captainhook/plugin-composer": "^5.3"
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"SPC\\": "src/SPC"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"src/globals/defines.php",
|
|
||||||
"src/globals/functions.php"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"bin": [
|
|
||||||
"bin/spc"
|
|
||||||
],
|
|
||||||
"scripts": {
|
|
||||||
"analyse": "phpstan analyse --memory-limit 300M",
|
|
||||||
"cs-fix": "php-cs-fixer fix",
|
|
||||||
"test": "bin/phpunit --no-coverage"
|
|
||||||
},
|
|
||||||
"config": {
|
|
||||||
"allow-plugins": {
|
|
||||||
"phpstan/extension-installer": true,
|
|
||||||
"captainhook/plugin-composer": true
|
|
||||||
},
|
|
||||||
"optimize-autoloader": true,
|
|
||||||
"sort-packages": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
401
config/ext.json
401
config/ext.json
@@ -1,401 +0,0 @@
|
|||||||
{
|
|
||||||
"bcmath": {
|
|
||||||
"type": "builtin"
|
|
||||||
},
|
|
||||||
"bz2": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "custom",
|
|
||||||
"lib-depends": [
|
|
||||||
"bzip2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"calendar": {
|
|
||||||
"type": "builtin"
|
|
||||||
},
|
|
||||||
"ctype": {
|
|
||||||
"type": "builtin"
|
|
||||||
},
|
|
||||||
"curl": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"curl"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"dba": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type-windows": "with"
|
|
||||||
},
|
|
||||||
"dom": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type-windows": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"libxml2",
|
|
||||||
"zlib"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"enchant": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"enchant2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"exif": {
|
|
||||||
"type": "builtin"
|
|
||||||
},
|
|
||||||
"ffi": {
|
|
||||||
"arg-type": "with",
|
|
||||||
"type": "builtin",
|
|
||||||
"lib-depends": [
|
|
||||||
"libffi"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"fileinfo": {
|
|
||||||
"type": "builtin"
|
|
||||||
},
|
|
||||||
"filter": {
|
|
||||||
"type": "builtin"
|
|
||||||
},
|
|
||||||
"ftp": {
|
|
||||||
"type": "builtin",
|
|
||||||
"lib-suggests": [
|
|
||||||
"openssl"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"gd": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type-windows": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"zlib",
|
|
||||||
"libpng"
|
|
||||||
],
|
|
||||||
"ext-depends": [
|
|
||||||
"zlib"
|
|
||||||
],
|
|
||||||
"lib-suggests": [
|
|
||||||
"gd",
|
|
||||||
"libavif",
|
|
||||||
"libwebp",
|
|
||||||
"libjpeg",
|
|
||||||
"xpm",
|
|
||||||
"freetype"
|
|
||||||
],
|
|
||||||
"lib-depends-windows": [
|
|
||||||
"libiconv",
|
|
||||||
"freetype",
|
|
||||||
"libjpeg",
|
|
||||||
"zlib",
|
|
||||||
"libpng",
|
|
||||||
"xpm"
|
|
||||||
],
|
|
||||||
"lib-suggests-windows": [
|
|
||||||
"gd",
|
|
||||||
"libavif",
|
|
||||||
"libwebp"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"gettext": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"gettext"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"gmp": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "none",
|
|
||||||
"lib-depends": [
|
|
||||||
"gmp"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"iconv": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"lib-depends-windows": [
|
|
||||||
"libiconv"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"imap": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"imap"
|
|
||||||
],
|
|
||||||
"lib-suggests": [
|
|
||||||
"kerberos"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"intl": {
|
|
||||||
"type": "builtin",
|
|
||||||
"lib-depends": [
|
|
||||||
"icu"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ldap": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"ldap"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"mbregex": {
|
|
||||||
"type": "builtin",
|
|
||||||
"lib-depends": [
|
|
||||||
"onig"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"mbstring": {
|
|
||||||
"type": "builtin",
|
|
||||||
"lib-depends": [
|
|
||||||
"onig"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"mongodb": {
|
|
||||||
"type": "external",
|
|
||||||
"source": "mongodb"
|
|
||||||
},
|
|
||||||
"mysqli": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"ext-depends": [
|
|
||||||
"mysqlnd"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"mysqlnd": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type-windows": "with"
|
|
||||||
},
|
|
||||||
"opcache": {
|
|
||||||
"type": "builtin"
|
|
||||||
},
|
|
||||||
"openssl": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"openssl"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"pcntl": {
|
|
||||||
"type": "builtin",
|
|
||||||
"unix-only": true
|
|
||||||
},
|
|
||||||
"pdo": {
|
|
||||||
"type": "builtin"
|
|
||||||
},
|
|
||||||
"pdo_mysql": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"ext-depends": [
|
|
||||||
"pdo",
|
|
||||||
"mysqlnd"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"pdo_pgsql": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"ext-depends": [
|
|
||||||
"pdo"
|
|
||||||
],
|
|
||||||
"lib-depends": [
|
|
||||||
"pq"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"pdo_sqlite": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"ext-depends": [
|
|
||||||
"pdo",
|
|
||||||
"sqlite3"
|
|
||||||
],
|
|
||||||
"lib-depends": [
|
|
||||||
"sqlite"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"phar": {
|
|
||||||
"type": "builtin",
|
|
||||||
"lib-suggests": [
|
|
||||||
"zlib"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"posix": {
|
|
||||||
"type": "builtin",
|
|
||||||
"unix-only": true
|
|
||||||
},
|
|
||||||
"pspell": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"aspell"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"readline": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"readline"
|
|
||||||
],
|
|
||||||
"lib-suggests": [
|
|
||||||
"libedit",
|
|
||||||
"ncurses"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"redis": {
|
|
||||||
"type": "external",
|
|
||||||
"source": "redis"
|
|
||||||
},
|
|
||||||
"session": {
|
|
||||||
"type": "builtin"
|
|
||||||
},
|
|
||||||
"shmop": {
|
|
||||||
"type": "builtin"
|
|
||||||
},
|
|
||||||
"simplexml": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type-windows": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"libxml2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"snmp": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"net-snmp"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"soap": {
|
|
||||||
"type": "builtin",
|
|
||||||
"lib-depends": [
|
|
||||||
"libxml2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sockets": {
|
|
||||||
"type": "builtin"
|
|
||||||
},
|
|
||||||
"sodium": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"sodium"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sqlite3": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"sqlite"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"swoole": {
|
|
||||||
"type": "external",
|
|
||||||
"source": "swoole",
|
|
||||||
"lib-depends": [
|
|
||||||
"openssl"
|
|
||||||
],
|
|
||||||
"ext-depends": [
|
|
||||||
"openssl"
|
|
||||||
],
|
|
||||||
"ext-suggests": [
|
|
||||||
"curl"
|
|
||||||
],
|
|
||||||
"unix-only": true
|
|
||||||
},
|
|
||||||
"swow": {
|
|
||||||
"type": "external",
|
|
||||||
"source": "swow",
|
|
||||||
"lib-depends": [
|
|
||||||
"libuv"
|
|
||||||
],
|
|
||||||
"lib-suggests": [
|
|
||||||
"openssl",
|
|
||||||
"curl"
|
|
||||||
],
|
|
||||||
"ext-suggests": [
|
|
||||||
"curl"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sysvmsg": {
|
|
||||||
"type": "builtin",
|
|
||||||
"unix-only": true
|
|
||||||
},
|
|
||||||
"sysvsem": {
|
|
||||||
"type": "builtin",
|
|
||||||
"unix-only": true
|
|
||||||
},
|
|
||||||
"sysvshm": {
|
|
||||||
"type": "builtin",
|
|
||||||
"unix-only": true
|
|
||||||
},
|
|
||||||
"tidy": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"tidy"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"tokenizer": {
|
|
||||||
"type": "builtin"
|
|
||||||
},
|
|
||||||
"xml": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type-windows": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"libxml2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"xmlreader": {
|
|
||||||
"type": "builtin",
|
|
||||||
"lib-depends": [
|
|
||||||
"libxml2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"xmlwriter": {
|
|
||||||
"type": "builtin",
|
|
||||||
"lib-depends": [
|
|
||||||
"libxml2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"xsl": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"libxslt"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"protobuf": {
|
|
||||||
"type": "external",
|
|
||||||
"source": "protobuf"
|
|
||||||
},
|
|
||||||
"yaml": {
|
|
||||||
"type": "external",
|
|
||||||
"source": "yaml",
|
|
||||||
"arg-type": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"libyaml"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"zip": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"arg-type-windows": "enable",
|
|
||||||
"lib-depends": [
|
|
||||||
"libzip"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"zlib": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"arg-type-windows": "enable",
|
|
||||||
"lib-depends": [
|
|
||||||
"zlib"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"zstd": {
|
|
||||||
"type": "external",
|
|
||||||
"source": "ext-zstd",
|
|
||||||
"lib-depends": [
|
|
||||||
"zstd"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
391
config/lib.json
391
config/lib.json
@@ -1,391 +0,0 @@
|
|||||||
{
|
|
||||||
"brotli": {
|
|
||||||
"source": "brotli",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libbrotlidec-static.a",
|
|
||||||
"libbrotlienc-static.a",
|
|
||||||
"libbrotlicommon-static.a"
|
|
||||||
],
|
|
||||||
"static-libs-windows": [
|
|
||||||
"brotlicommon-static.lib",
|
|
||||||
"brotlienc-static.lib",
|
|
||||||
"brotlidec-static.lib"
|
|
||||||
],
|
|
||||||
"headers": [
|
|
||||||
"brotli"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"bzip2": {
|
|
||||||
"source": "bzip2",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libbz2.a"
|
|
||||||
],
|
|
||||||
"static-libs-windows": [
|
|
||||||
[
|
|
||||||
"libbz2.lib",
|
|
||||||
"libbz2_a.lib"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"headers": [
|
|
||||||
"bzlib.h"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"curl": {
|
|
||||||
"source": "curl",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libcurl.a"
|
|
||||||
],
|
|
||||||
"static-libs-windows": [
|
|
||||||
"libcurl.lib"
|
|
||||||
],
|
|
||||||
"headers": [
|
|
||||||
"curl"
|
|
||||||
],
|
|
||||||
"lib-depends-unix": [
|
|
||||||
"zlib"
|
|
||||||
],
|
|
||||||
"lib-suggests": [
|
|
||||||
"libssh2",
|
|
||||||
"brotli",
|
|
||||||
"nghttp2",
|
|
||||||
"zstd",
|
|
||||||
"openssl",
|
|
||||||
"idn2",
|
|
||||||
"psl"
|
|
||||||
],
|
|
||||||
"lib-suggests-windows": [
|
|
||||||
"zlib",
|
|
||||||
"libssh2",
|
|
||||||
"brotli",
|
|
||||||
"nghttp2",
|
|
||||||
"zstd",
|
|
||||||
"openssl",
|
|
||||||
"idn2",
|
|
||||||
"psl"
|
|
||||||
],
|
|
||||||
"frameworks": [
|
|
||||||
"CoreFoundation",
|
|
||||||
"SystemConfiguration"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"gmp": {
|
|
||||||
"source": "gmp",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libgmp.a"
|
|
||||||
],
|
|
||||||
"static-libs-windows": [
|
|
||||||
"libgmp.lib"
|
|
||||||
],
|
|
||||||
"headers": [
|
|
||||||
"gmp.h"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"libffi": {
|
|
||||||
"source": "libffi",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libffi.a"
|
|
||||||
],
|
|
||||||
"static-libs-windows": [
|
|
||||||
"libffi.lib"
|
|
||||||
],
|
|
||||||
"headers-unix": [
|
|
||||||
"ffi.h",
|
|
||||||
"ffitarget.h"
|
|
||||||
],
|
|
||||||
"headers-windows": [
|
|
||||||
"ffi.h",
|
|
||||||
"fficonfig.h",
|
|
||||||
"ffitarget.h"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
"libpng": {
|
|
||||||
"source": "libpng",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libpng.a"
|
|
||||||
],
|
|
||||||
"static-libs-windows": [
|
|
||||||
"libpng16_static.lib"
|
|
||||||
],
|
|
||||||
"headers-unix": [
|
|
||||||
"png.h",
|
|
||||||
"pngconf.h",
|
|
||||||
"pnglibconf.h"
|
|
||||||
],
|
|
||||||
"headers-windows": [
|
|
||||||
"png.h",
|
|
||||||
"pngconf.h"
|
|
||||||
],
|
|
||||||
"lib-depends": [
|
|
||||||
"zlib"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"libssh2": {
|
|
||||||
"source": "libssh2",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libssh2.a"
|
|
||||||
],
|
|
||||||
"static-libs-windows": [
|
|
||||||
"libssh2.lib"
|
|
||||||
],
|
|
||||||
"headers": [
|
|
||||||
"libssh2.h",
|
|
||||||
"libssh2_publickey.h",
|
|
||||||
"libssh2_sftp.h"
|
|
||||||
],
|
|
||||||
"lib-depends": [
|
|
||||||
"openssl"
|
|
||||||
],
|
|
||||||
"lib-suggests": [
|
|
||||||
"zlib"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"libxml2": {
|
|
||||||
"source": "libxml2",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libxml2.a"
|
|
||||||
],
|
|
||||||
"static-libs-windows": [
|
|
||||||
[
|
|
||||||
"libxml2s.lib",
|
|
||||||
"libxml2_a.lib"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"headers": [
|
|
||||||
"libxml2"
|
|
||||||
],
|
|
||||||
"lib-depends": [
|
|
||||||
"libiconv"
|
|
||||||
],
|
|
||||||
"lib-suggests": [
|
|
||||||
"icu",
|
|
||||||
"xz",
|
|
||||||
"zlib"
|
|
||||||
],
|
|
||||||
"lib-suggests-windows": [
|
|
||||||
"icu",
|
|
||||||
"xz",
|
|
||||||
"zlib",
|
|
||||||
"pthreads4w"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"libiconv": {
|
|
||||||
"source": "libiconv",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libiconv.a"
|
|
||||||
],
|
|
||||||
"headers": [
|
|
||||||
"iconv.h",
|
|
||||||
"libcharset.h",
|
|
||||||
"localcharset.h"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"libyaml": {
|
|
||||||
"source": "libyaml",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libyaml.a"
|
|
||||||
],
|
|
||||||
"static-libs-windows": [
|
|
||||||
"yaml.lib"
|
|
||||||
],
|
|
||||||
"headers": [
|
|
||||||
"yaml.h"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"libzip": {
|
|
||||||
"source": "libzip",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libzip.a"
|
|
||||||
],
|
|
||||||
"static-libs-windows": [
|
|
||||||
[
|
|
||||||
"zip.lib",
|
|
||||||
"libzip_a.lib"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"headers": [
|
|
||||||
"zip.h",
|
|
||||||
"zipconf.h"
|
|
||||||
],
|
|
||||||
"lib-depends": [
|
|
||||||
"zlib"
|
|
||||||
],
|
|
||||||
"lib-suggests": [
|
|
||||||
"bzip2",
|
|
||||||
"xz",
|
|
||||||
"zstd",
|
|
||||||
"openssl"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"libmcrypt": {
|
|
||||||
"source": "libmcrypt",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libmcrypt.a"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"mcrypt": {
|
|
||||||
"source": "mcrypt",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libmcrypt.a"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"freetype": {
|
|
||||||
"source": "freetype",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libfreetype.a"
|
|
||||||
],
|
|
||||||
"headers-unix": [
|
|
||||||
"freetype2/freetype/freetype.h",
|
|
||||||
"freetype2/ft2build.h"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nghttp2": {
|
|
||||||
"source": "nghttp2",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libnghttp2.a"
|
|
||||||
],
|
|
||||||
"static-libs-windows": [
|
|
||||||
"nghttp2.lib"
|
|
||||||
],
|
|
||||||
"headers": [
|
|
||||||
"nghttp2"
|
|
||||||
],
|
|
||||||
"lib-depends": [
|
|
||||||
"zlib",
|
|
||||||
"openssl"
|
|
||||||
],
|
|
||||||
"lib-suggests": [
|
|
||||||
"libxml2",
|
|
||||||
"libev",
|
|
||||||
"libcares",
|
|
||||||
"libngtcp2",
|
|
||||||
"libnghttp3",
|
|
||||||
"libbpf",
|
|
||||||
"libevent-openssl",
|
|
||||||
"jansson",
|
|
||||||
"jemalloc",
|
|
||||||
"systemd",
|
|
||||||
"cunit"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"libuv": {
|
|
||||||
"source": "libuv",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libuv.a"
|
|
||||||
],
|
|
||||||
"headers": [
|
|
||||||
"uv.h"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"onig": {
|
|
||||||
"source": "onig",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libonig.a"
|
|
||||||
],
|
|
||||||
"static-libs-windows": [
|
|
||||||
[
|
|
||||||
"onig.lib",
|
|
||||||
"onig_a.lib"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"headers": [
|
|
||||||
"oniggnu.h",
|
|
||||||
"oniguruma.h"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"openssl": {
|
|
||||||
"source": "openssl",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libssl.a",
|
|
||||||
"libcrypto.a"
|
|
||||||
],
|
|
||||||
"static-libs-windows": [
|
|
||||||
"libssl.lib",
|
|
||||||
"libcrypto.lib"
|
|
||||||
],
|
|
||||||
"headers": [
|
|
||||||
"openssl"
|
|
||||||
],
|
|
||||||
"lib-suggests": [
|
|
||||||
"zlib"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"pthreads4w": {
|
|
||||||
"source": "pthreads4w",
|
|
||||||
"static-libs-windows": [
|
|
||||||
"libpthreadVC3.lib"
|
|
||||||
],
|
|
||||||
"headers-windows": [
|
|
||||||
"_ptw32.h",
|
|
||||||
"pthread.h",
|
|
||||||
"sched.h",
|
|
||||||
"semaphore.h"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sqlite": {
|
|
||||||
"source": "sqlite",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libsqlite3.a"
|
|
||||||
],
|
|
||||||
"headers-unix": [
|
|
||||||
"sqlite3.h",
|
|
||||||
"sqlite3ext.h"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"xz": {
|
|
||||||
"source": "xz",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"liblzma.a"
|
|
||||||
],
|
|
||||||
"static-libs-windows": [
|
|
||||||
[
|
|
||||||
"liblzma.lib",
|
|
||||||
"liblzma_a.lib"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"headers-unix": [
|
|
||||||
"lzma"
|
|
||||||
],
|
|
||||||
"headers-windows": [
|
|
||||||
"lzma",
|
|
||||||
"lzma.h"
|
|
||||||
],
|
|
||||||
"lib-depends": [
|
|
||||||
"libiconv"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"zlib": {
|
|
||||||
"source": "zlib",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libz.a"
|
|
||||||
],
|
|
||||||
"static-libs-windows": [
|
|
||||||
"zlib_a.lib"
|
|
||||||
],
|
|
||||||
"headers": [
|
|
||||||
"zlib.h",
|
|
||||||
"zconf.h"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"zstd": {
|
|
||||||
"source": "zstd",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libzstd.a"
|
|
||||||
],
|
|
||||||
"static-libs-windows": [
|
|
||||||
[
|
|
||||||
"zstd.lib",
|
|
||||||
"zstd_static.lib"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"headers-unix": [
|
|
||||||
"zdict.h",
|
|
||||||
"zstd.h",
|
|
||||||
"zstd_errors.h"
|
|
||||||
],
|
|
||||||
"headers-windows": [
|
|
||||||
"zstd.h",
|
|
||||||
"zstd_errors.h"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
137
docker/Dockerfile
Normal file
137
docker/Dockerfile
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
from alpine:latest
|
||||||
|
|
||||||
|
# define script basic information
|
||||||
|
# Version of this Dockerfile
|
||||||
|
ENV SCRIPT_VERSION=1.3.0
|
||||||
|
# Download address uses backup address
|
||||||
|
# (if downloading slowly, consider set it to yes)
|
||||||
|
ENV USE_BACKUP=no
|
||||||
|
|
||||||
|
# Version of some manually-installed package
|
||||||
|
ENV VER_PHP=7.4.19
|
||||||
|
ENV VER_SWOOLE=4.6.7
|
||||||
|
ENV VER_HASH=1.5
|
||||||
|
ENV VER_INOTIFY=3.0.0
|
||||||
|
ENV VER_REDIS=5.3.4
|
||||||
|
ENV VER_LIBXML2=2.9.12
|
||||||
|
ENV VER_CURL=7.77.0
|
||||||
|
ENV VER_LIBLZMA=master
|
||||||
|
|
||||||
|
# LINK_OF_ADDRESS_ORIGIN
|
||||||
|
ENV LINK_APK_REPO='mirrors.ustc.edu.cn'
|
||||||
|
ENV LINK_APK_REPO_BAK='dl-cdn.alpinelinux.org'
|
||||||
|
|
||||||
|
RUN if [ "${USE_BACKUP}" = "yes" ]; then \
|
||||||
|
echo "Using backup address..." && sleep 3s; \
|
||||||
|
else \
|
||||||
|
echo "Using original address..." && sleep 3s; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
RUN sed -i 's/dl-cdn.alpinelinux.org/'${LINK_APK_REPO}'/g' /etc/apk/repositories
|
||||||
|
|
||||||
|
# build requirements
|
||||||
|
RUN apk add cmake gcc g++ jq autoconf git libstdc++ linux-headers make m4 libgcc binutils ncurses
|
||||||
|
# php zlib dependencies
|
||||||
|
RUN apk add zlib-dev zlib-static
|
||||||
|
# php mbstring dependencies
|
||||||
|
RUN apk add oniguruma-dev
|
||||||
|
# php openssl dependencies
|
||||||
|
RUN apk add openssl-libs-static openssl-dev openssl
|
||||||
|
# php gd dependencies
|
||||||
|
RUN apk add libpng-dev libpng-static
|
||||||
|
# curl c-ares dependencies
|
||||||
|
RUN apk add c-ares-static c-ares-dev
|
||||||
|
|
||||||
|
RUN mkdir /app
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY download.sh /app/
|
||||||
|
COPY compile-php.sh /app/
|
||||||
|
|
||||||
|
RUN chmod +x /app/download.sh && \
|
||||||
|
chmod +x /app/compile-php.sh
|
||||||
|
|
||||||
|
RUN ./download.sh swoole ${USE_BACKUP} ${VER_SWOOLE}
|
||||||
|
RUN ./download.sh hash ${USE_BACKUP} ${VER_HASH}
|
||||||
|
RUN ./download.sh swoole ${USE_BACKUP} ${VER_SWOOLE}
|
||||||
|
RUN ./download.sh swoole ${USE_BACKUP} ${VER_SWOOLE}
|
||||||
|
RUN ./download.sh swoole ${USE_BACKUP} ${VER_SWOOLE}
|
||||||
|
RUN ./download.sh swoole ${USE_BACKUP} ${VER_SWOOLE}
|
||||||
|
RUN ./download.sh swoole ${USE_BACKUP} ${VER_SWOOLE}
|
||||||
|
|
||||||
|
RUN wget "http://mirrors.zhamao.xin/php/php-${VER_PHP}.tar.gz" -O php.tar.gz
|
||||||
|
RUN wget "http://mirrors.zhamao.xin/pecl/swoole-${VER_SWOOLE}.tgz" -O swoole.tar.gz
|
||||||
|
RUN wget "http://mirrors.zhamao.xin/pecl/hash-${VER_HASH}.tgz" -O hash.tar.gz
|
||||||
|
RUN wget "http://mirrors.zhamao.xin/pecl/inotify-${VER_INOTIFY}.tgz" -O inotify.tar.gz
|
||||||
|
RUN wget "http://mirrors.zhamao.xin/pecl/redis-${VER_REDIS}.tgz" -O redis.tar.gz
|
||||||
|
RUN wget "https://dl.zhamao.me/libxml2/libxml2-${VER_LIBXML2}.tar.gz" -O libxml2.tar.gz
|
||||||
|
RUN wget "https://dl.zhamao.me/liblzma/liblzma.tar.gz"
|
||||||
|
RUN wget "https://dl.zhamao.me/curl/curl-${VER_CURL}.tar.gz" -O curl.tar.gz
|
||||||
|
|
||||||
|
RUN tar -xf php.tar.gz && \
|
||||||
|
tar -xf swoole.tar.gz && \
|
||||||
|
tar -xf hash.tar.gz && \
|
||||||
|
tar -xf inotify.tar.gz && \
|
||||||
|
tar -xf redis.tar.gz && \
|
||||||
|
tar -xf libxml2.tar.gz && \
|
||||||
|
tar -xf liblzma.tar.gz && \
|
||||||
|
tar -xf curl.tar.gz
|
||||||
|
|
||||||
|
RUN cd liblzma && \
|
||||||
|
./configure && \
|
||||||
|
make -j4 && \
|
||||||
|
make install && \
|
||||||
|
echo "liblzma compiled!"
|
||||||
|
|
||||||
|
RUN cd "libxml2-${VER_LIBXML2}" && \
|
||||||
|
./configure --with-lzma --without-python && \
|
||||||
|
make -j4 && \
|
||||||
|
make install && \
|
||||||
|
echo "libxml2 compiled!"
|
||||||
|
|
||||||
|
RUN cd "curl-${VER_CURL}" && \
|
||||||
|
CC=gcc CXX=g++ CFLAGS=-fPIC CPPFLAGS=-fPIC ./configure \
|
||||||
|
--without-nghttp2 \
|
||||||
|
--with-ssl=/usr \
|
||||||
|
--with-pic=pic \
|
||||||
|
--enable-ipv6 \
|
||||||
|
--enable-shared=no \
|
||||||
|
--without-libidn2 \
|
||||||
|
--disable-ldap \
|
||||||
|
--without-libpsl \
|
||||||
|
--without-lber \
|
||||||
|
--enable-ares && \
|
||||||
|
make -j4 && \
|
||||||
|
make install && \
|
||||||
|
echo "curl compiled!"
|
||||||
|
|
||||||
|
COPY ac_override_1 /
|
||||||
|
COPY ac_override_2 /
|
||||||
|
COPY compile-php.sh /app/
|
||||||
|
|
||||||
|
RUN apk add bash
|
||||||
|
|
||||||
|
# copy
|
||||||
|
RUN mv "swoole-${VER_SWOOLE}" "php-${VER_PHP}/ext/swoole" && \
|
||||||
|
mv "redis-${VER_REDIS}" "php-${VER_PHP}/ext/redis" && \
|
||||||
|
mv "inotify-${VER_INOTIFY}" "php-${VER_PHP}/ext/inotify"
|
||||||
|
|
||||||
|
RUN cat /ac_override_1 /app/php-${VER_PHP}/ext/curl/config.m4 /ac_override_2 > /app/aa
|
||||||
|
RUN mv /app/aa /app/php-${VER_PHP}/ext/curl/config.m4
|
||||||
|
|
||||||
|
RUN cd "php-${VER_PHP}/ext/swoole/" && \
|
||||||
|
./clear.sh && \
|
||||||
|
cd ../../ && \
|
||||||
|
./buildconf --force
|
||||||
|
|
||||||
|
RUN ./compile-php.sh ${VER_PHP}
|
||||||
|
|
||||||
|
RUN cd "php-${VER_PHP}" && \
|
||||||
|
sed -ie 's/-export-dynamic//g' "Makefile" && \
|
||||||
|
sed -ie 's/-o \$(SAPI_CLI_PATH)/-all-static -o \$(SAPI_CLI_PATH)/g' "Makefile" && \
|
||||||
|
sed -ie 's/swoole_clock_gettime(CLOCK_REALTIME/clock_gettime(CLOCK_REALTIME/g' "ext/swoole/include/swoole.h" && \
|
||||||
|
make LDFLAGS=-ldl -j4 && \
|
||||||
|
make install && \
|
||||||
|
strip
|
||||||
|
|
||||||
3
docker/ac_override_1
Normal file
3
docker/ac_override_1
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
AC_DEFUN([PHP_CHECK_LIBRARY], [
|
||||||
|
$3
|
||||||
|
])
|
||||||
18
docker/ac_override_2
Normal file
18
docker/ac_override_2
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
AC_DEFUN([PHP_CHECK_LIBRARY], [
|
||||||
|
save_old_LDFLAGS=$LDFLAGS
|
||||||
|
ac_stuff="$5"
|
||||||
|
|
||||||
|
save_ext_shared=$ext_shared
|
||||||
|
ext_shared=yes
|
||||||
|
PHP_EVAL_LIBLINE([$]ac_stuff, LDFLAGS)
|
||||||
|
AC_CHECK_LIB([$1],[$2],[
|
||||||
|
LDFLAGS=$save_old_LDFLAGS
|
||||||
|
ext_shared=$save_ext_shared
|
||||||
|
$3
|
||||||
|
],[
|
||||||
|
LDFLAGS=$save_old_LDFLAGS
|
||||||
|
ext_shared=$save_ext_shared
|
||||||
|
unset ac_cv_lib_$1[]_$2
|
||||||
|
$4
|
||||||
|
])dnl
|
||||||
|
])
|
||||||
87
docker/compile-php.sh
Normal file
87
docker/compile-php.sh
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
VER_PHP="$1"
|
||||||
|
|
||||||
|
function php_compile_args() {
|
||||||
|
_php_arg="--prefix=/app/php-dist"
|
||||||
|
_php_arg="$_php_arg --disable-all"
|
||||||
|
_php_arg="$_php_arg --enable-shared=no"
|
||||||
|
_php_arg="$_php_arg --enable-static=yes"
|
||||||
|
_php_arg="$_php_arg --enable-inline-optimization"
|
||||||
|
_php_arg="$_php_arg --with-layout=GNU"
|
||||||
|
_php_arg="$_php_arg --enable-calendar"
|
||||||
|
_php_arg="$_php_arg --enable-ctype"
|
||||||
|
_php_arg="$_php_arg --enable-filter"
|
||||||
|
_php_arg="$_php_arg --enable-openssl"
|
||||||
|
_php_arg="$_php_arg --enable-bcmath"
|
||||||
|
_php_arg="$_php_arg --enable-pcntl"
|
||||||
|
_php_arg="$_php_arg --enable-openssl"
|
||||||
|
_php_arg="$_php_arg --with-openssl"
|
||||||
|
_php_arg="$_php_arg --with-iconv"
|
||||||
|
_php_arg="$_php_arg --enable-mbstring"
|
||||||
|
_php_arg="$_php_arg --enable-phar"
|
||||||
|
_php_arg="$_php_arg --enable-pdo"
|
||||||
|
_php_arg="$_php_arg --with-pdo-mysql=mysqlnd"
|
||||||
|
_php_arg="$_php_arg --enable-sockets"
|
||||||
|
_php_arg="$_php_arg --enable-swoole"
|
||||||
|
_php_arg="$_php_arg --enable-inotify"
|
||||||
|
_php_arg="$_php_arg --enable-redis"
|
||||||
|
_php_arg="$_php_arg --disable-redis-session"
|
||||||
|
_php_arg="$_php_arg --enable-simplexml"
|
||||||
|
_php_arg="$_php_arg --enable-dom"
|
||||||
|
_php_arg="$_php_arg --enable-xml"
|
||||||
|
_php_arg="$_php_arg --enable-xmlwriter"
|
||||||
|
_php_arg="$_php_arg --enable-xmlreader"
|
||||||
|
_php_arg="$_php_arg --with-zlib"
|
||||||
|
_php_arg="$_php_arg --enable-posix"
|
||||||
|
_php_arg="$_php_arg --enable-mysqlnd"
|
||||||
|
_php_arg="$_php_arg --enable-tokenizer"
|
||||||
|
_php_arg="$_php_arg --with-curl"
|
||||||
|
_php_arg="$_php_arg --with-pear=no"
|
||||||
|
_php_arg="$_php_arg --disable-cgi"
|
||||||
|
_php_arg="$_php_arg --disable-phpdbg"
|
||||||
|
|
||||||
|
for loop in $(cat extension.txt)
|
||||||
|
do
|
||||||
|
case $loop in
|
||||||
|
swoole)
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
7.3.*|7.2.*)
|
||||||
|
_php_arg="$_php_arg --with-gd"
|
||||||
|
_php_arg="$_php_arg --enable-libxml"
|
||||||
|
_php_arg="$_php_arg --enable-hash"
|
||||||
|
_php_arg="$_php_arg --enable-json"
|
||||||
|
;;
|
||||||
|
7.4.*)
|
||||||
|
_php_arg="$_php_arg --enable-gd"
|
||||||
|
_php_arg="$_php_arg --with-libxml"
|
||||||
|
_php_arg="$_php_arg --enable-json"
|
||||||
|
;;
|
||||||
|
8.*)
|
||||||
|
_php_arg="$_php_arg --enable-gd"
|
||||||
|
_php_arg="$_php_arg --with-libxml"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo $_php_arg
|
||||||
|
}
|
||||||
|
|
||||||
|
function before_configure() {
|
||||||
|
for loop in $(cat extension.txt)
|
||||||
|
do
|
||||||
|
case $loop in
|
||||||
|
swoole)
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
cd php-$VER_PHP && \
|
||||||
|
before_configure && \
|
||||||
|
./buildconf --force && \
|
||||||
|
./configure LDFLAGS=-static $(php_compile_args $VER_PHP) && \
|
||||||
|
after_configure && \
|
||||||
|
sed -ie 's/-export-dynamic//g' "Makefile" && \
|
||||||
|
sed -ie 's/-o $(SAPI_CLI_PATH)/-all-static -o $(SAPI_CLI_PATH)/g' "Makefile" && \
|
||||||
|
if [ "$(cat extension.txt | grep swoole)" != "" ]; then sed -ie 's/swoole_clock_gettime(CLOCK_REALTIME/clock_gettime(CLOCK_REALTIME/g' "ext/swoole/include/swoole.h" && \
|
||||||
3
docker/config.json
Normal file
3
docker/config.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
swoole
|
||||||
|
redis
|
||||||
|
hello
|
||||||
109
docker/download.sh
Normal file
109
docker/download.sh
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
_use_backup="$2"
|
||||||
|
|
||||||
|
function download_file() {
|
||||||
|
downloader="wget"
|
||||||
|
type wget >/dev/null 2>&1 || { downloader="curl"; }
|
||||||
|
if [ "$downloader" = "wget" ]; then
|
||||||
|
_down_prefix="O"
|
||||||
|
else
|
||||||
|
_down_prefix="o"
|
||||||
|
fi
|
||||||
|
_down_symbol=0
|
||||||
|
if [ ! -f "$2" ]; then
|
||||||
|
$downloader "$1" -$_down_prefix "$2" >/dev/null 2>&1 && \
|
||||||
|
echo "$1 完成! $2" && _down_symbol=1
|
||||||
|
else
|
||||||
|
echo "$2 已存在!" && _down_symbol=1
|
||||||
|
fi
|
||||||
|
if [ $_down_symbol == 0 ]; then
|
||||||
|
echo "下载 $1 失败!请检查网络连接!"
|
||||||
|
rm -rf "$2"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function lib_download_link() {
|
||||||
|
if [ "$_use_backup" = "yes" ]; then
|
||||||
|
case $1 in
|
||||||
|
"php") echo "https://www.php.net/distributions/php-$2.tar.gz" ;;
|
||||||
|
"swoole") echo "https://pecl.php.net/get/swoole-$2.tgz" ;;
|
||||||
|
"hash") echo "https://pecl.php.net/get/hash-$2.tgz" ;;
|
||||||
|
"inotify") echo "https://pecl.php.net/get/inotify-$2.tgz" ;;
|
||||||
|
"redis") echo "https://pecl.php.net/get/redis-$2.tgz" ;;
|
||||||
|
"libxml2") echo "http://xmlsoft.org/sources/libxml2-$2.tar.gz" ;;
|
||||||
|
"liblzma") echo "https://github.com/kobolabs/liblzma/archive/refs/heads/master.zip" ;;
|
||||||
|
"curl") echo "https://curl.haxx.se/download/curl-$2.tar.gz" ;;
|
||||||
|
*) echo "unknown" ;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
case $1 in
|
||||||
|
"php") echo "http://mirrors.zhamao.xin/php/php-$2.tar.gz" ;;
|
||||||
|
"swoole") echo "http://mirrors.zhamao.xin/pecl/swoole-$2.tgz" ;;
|
||||||
|
"hash") echo "http://mirrors.zhamao.xin/pecl/hash-$2.tgz" ;;
|
||||||
|
"inotify") echo "http://mirrors.zhamao.xin/pecl/inotify-$2.tgz" ;;
|
||||||
|
"redis") echo "http://mirrors.zhamao.xin/pecl/redis-$2.tgz" ;;
|
||||||
|
"libxml2") echo "https://dl.zhamao.me/libxml2/libxml2-$2.tar.gz" ;;
|
||||||
|
"liblzma") echo "https://dl.zhamao.me/liblzma/liblzma.tar.gz" ;;
|
||||||
|
"curl") echo "https://dl.zhamao.me/curl/curl-$2.tar.gz" ;;
|
||||||
|
*) echo "unknown" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function lib_x_cmd() {
|
||||||
|
case $1 in
|
||||||
|
"php"|"swoole"|"hash"|"inotify"|"redis"|"libxml2"|"curl")
|
||||||
|
_x_cmd="tar"
|
||||||
|
;;
|
||||||
|
"liblzma") if [ "$_use_backup" = "yes" ]; then _x_cmd="unzip"; else _x_cmd="tar"; fi ;;
|
||||||
|
*) _x_cmd="unknown" ;;
|
||||||
|
esac
|
||||||
|
case $2 in
|
||||||
|
"cmd")
|
||||||
|
echo $_x_cmd
|
||||||
|
;;
|
||||||
|
"file-prefix")
|
||||||
|
case $_x_cmd in
|
||||||
|
"tar") echo "-zxvf" ;;
|
||||||
|
"unzip") echo "" ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
"out-prefix")
|
||||||
|
case $_x_cmd in
|
||||||
|
"tar") echo "-C" ;;
|
||||||
|
"unzip") echo "-d" ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
function lib_x() {
|
||||||
|
$(lib_x_cmd $1 cmd) $(lib_x_cmd $1 file-prefix) "$_source_dir/$(lib_x_dirname $1 file)" $(lib_x_cmd $1 out-prefix) "$_source_dir/"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 获取解压后的源码根目录
|
||||||
|
function lib_x_dirname() {
|
||||||
|
case $1 in
|
||||||
|
"php"|"swoole"|"hash"|"inotify"|"redis"|"libxml2"|"curl")
|
||||||
|
if [ "$2" = "file" ]; then _name_prefix=".tar.gz"; else _name_prefix=""; fi
|
||||||
|
echo "$1-$(lib_ver $1)$_name_prefix"
|
||||||
|
;;
|
||||||
|
"liblzma")
|
||||||
|
if [ "$_use_backup" = "yes" ]; then
|
||||||
|
if [ "$2" = "file" ]; then _name_prefix=".zip"; else _name_prefix=""; fi
|
||||||
|
echo "$1-$(lib_ver $1)$_name_prefix"
|
||||||
|
else
|
||||||
|
if [ "$2" = "file" ]; then _name_prefix=".tar.gz"; else _name_prefix=""; fi
|
||||||
|
echo "$1""$_name_prefix"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "unknown"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
download_file $(lib_download_link $1 $3) $(lib_x_firname $1 file)
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
# Extension List
|
|
||||||
|
|
||||||
> - yes: supported and tested
|
|
||||||
> - untested: supported, but not tested
|
|
||||||
> - empty: not supported yet
|
|
||||||
> - faulty with issue link: not supported yet due to issue
|
|
||||||
|
|
||||||
| | Linux | macOS | Windows |
|
|
||||||
|------------|--------------------------------------------------------------------|--------------------------------------------------------------------|---------|
|
|
||||||
| bcmath | yes | yes | |
|
|
||||||
| bz2 | yes | untested | |
|
|
||||||
| calendar | yes | yes | |
|
|
||||||
| ctype | yes | yes | |
|
|
||||||
| curl | untested | yes | |
|
|
||||||
| date | yes | yes | |
|
|
||||||
| dba | yes | yes | |
|
|
||||||
| dom | untested | untested | |
|
|
||||||
| enchant | | | |
|
|
||||||
| event | | | |
|
|
||||||
| exif | yes | yes | |
|
|
||||||
| filter | yes | yes | |
|
|
||||||
| fileinfo | yes | | |
|
|
||||||
| ftp | yes | yes | |
|
|
||||||
| gd | untested | untested | |
|
|
||||||
| gettext | | | |
|
|
||||||
| gmp | untested | untested | |
|
|
||||||
| hash | yes | yes | |
|
|
||||||
| iconv | untested | | |
|
|
||||||
| inotify | | | |
|
|
||||||
| mbstring | yes | yes | |
|
|
||||||
| mcrypt | | [faulty](https://github.com/crazywhalecc/static-php-cli/issues/32) | |
|
|
||||||
| mongodb | untested | | |
|
|
||||||
| mysqli | | | |
|
|
||||||
| mysqlnd | yes | yes | |
|
|
||||||
| openssl | untested | yes | |
|
|
||||||
| pcntl | untested | untested | |
|
|
||||||
| pdo | yes | yes | |
|
|
||||||
| pdo_mysql | yes | yes | |
|
|
||||||
| pdo_sqlite | yes | yes | |
|
|
||||||
| pdo_pgsql | | | |
|
|
||||||
| phar | yes | yes | |
|
|
||||||
| posix | yes | yes | |
|
|
||||||
| protobuf | untested | | |
|
|
||||||
| readline | | | |
|
|
||||||
| redis | yes | yes | |
|
|
||||||
| session | yes | yes | |
|
|
||||||
| shmop | untested | | |
|
|
||||||
| simplexml | untested | untested | |
|
|
||||||
| soap | untested | | |
|
|
||||||
| sockets | untested | | |
|
|
||||||
| sqlite3 | untested | untested | |
|
|
||||||
| swow | | | |
|
|
||||||
| swoole | [faulty](https://github.com/crazywhalecc/static-php-cli/issues/32) | [faulty](https://github.com/crazywhalecc/static-php-cli/issues/32) | |
|
|
||||||
| tokenizer | yes | yes | |
|
|
||||||
| xml | yes | yes | |
|
|
||||||
| xmlreader | untested | untested | |
|
|
||||||
| xmlwriter | untested | untested | |
|
|
||||||
| zip | untested | yes | |
|
|
||||||
| zlib | yes | yes | |
|
|
||||||
|
|
||||||
## Additional Requirements
|
|
||||||
|
|
||||||
- phpmicro requires PHP >= 8.0
|
|
||||||
- swoole >= 5.0 requires PHP >= 8.0
|
|
||||||
- swow requires PHP >= 8.0
|
|
||||||
|
|
||||||
## Bugs
|
|
||||||
|
|
||||||
See [#32](https://github.com/crazywhalecc/static-php-cli/issues/32).
|
|
||||||
23
multi-version-build.sh
Executable file
23
multi-version-build.sh
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
_main_dir="$(pwd)/"
|
||||||
|
|
||||||
|
_build_dir="$_main_dir/build"
|
||||||
|
|
||||||
|
mkdir "$_build_dir" > /dev/null 2>&1
|
||||||
|
|
||||||
|
for loop in "7.2.34" "7.3.28" "7.4.19" "8.0.6"
|
||||||
|
do
|
||||||
|
sed -i 's/phpver"|"php") echo ".*/phpver"|"php") echo "'$loop'" ;;/g' "$_main_dir""static-compile-php.sh" && \
|
||||||
|
rm -rf "$_main_dir""source/php.tar.gz" "$_main_dir""source/php-*" "$_main_dir""php-dist" && \
|
||||||
|
"$_main_dir""static-compile-php.sh" && \
|
||||||
|
cp "$_main_dir""php-dist/bin/php" "$_build_dir/" && \
|
||||||
|
cd "$_build_dir/" && \
|
||||||
|
tar -zcvf "php-$loop-static-bin-"$(uname -m)".tar.gz" "./php" && \
|
||||||
|
mv "./php" "./php-$loop" && \
|
||||||
|
cd "$_main_dir"
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Compile static php-$loop failed!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
12
phpstan.neon
12
phpstan.neon
@@ -1,12 +0,0 @@
|
|||||||
parameters:
|
|
||||||
reportUnmatchedIgnoredErrors: false
|
|
||||||
level: 4
|
|
||||||
paths:
|
|
||||||
- ./src/
|
|
||||||
ignoreErrors:
|
|
||||||
- '#Constant .* not found#'
|
|
||||||
- '#Unsafe usage of new static#'
|
|
||||||
- '#class Fiber#'
|
|
||||||
- '#Attribute class JetBrains\\PhpStorm\\ArrayShape does not exist#'
|
|
||||||
dynamicConstantNames:
|
|
||||||
- PHP_OS_FAMILY
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC;
|
|
||||||
|
|
||||||
use SPC\command\DeployCommand;
|
|
||||||
use SPC\store\FileSystem;
|
|
||||||
use Symfony\Component\Console\Application;
|
|
||||||
use Symfony\Component\Console\Command\Command;
|
|
||||||
use Symfony\Component\Console\Command\HelpCommand;
|
|
||||||
use Symfony\Component\Console\Command\ListCommand;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* spc 应用究级入口
|
|
||||||
*/
|
|
||||||
class ConsoleApplication extends Application
|
|
||||||
{
|
|
||||||
public const VERSION = '2.0-alpha2';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws \ReflectionException
|
|
||||||
* @throws exception\FileSystemException
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
parent::__construct('static-php-cli', self::VERSION);
|
|
||||||
|
|
||||||
global $argv;
|
|
||||||
|
|
||||||
// 生产环境不显示详细的调试错误,只使用 symfony console 自带的错误显示
|
|
||||||
$this->setCatchExceptions(file_exists(ROOT_DIR . '/.prod') || !in_array('--debug', $argv));
|
|
||||||
|
|
||||||
// 通过扫描目录 src/static-php-cli/command/ 添加子命令
|
|
||||||
$commands = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/command', 'SPC\\command');
|
|
||||||
$this->addCommands(array_map(function ($x) { return new $x(); }, array_filter($commands, function ($y) {
|
|
||||||
if (is_a($y, DeployCommand::class, true) && (class_exists('\\Phar') && \Phar::running() || !class_exists('\\Phar'))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$reflection = new \ReflectionClass($y);
|
|
||||||
return !$reflection->isAbstract() && !$reflection->isInterface();
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重载以去除一些不必要的默认命令
|
|
||||||
*/
|
|
||||||
protected function getDefaultCommands(): array
|
|
||||||
{
|
|
||||||
return [new HelpCommand(), new ListCommand()];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,227 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder;
|
|
||||||
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\store\Config;
|
|
||||||
use SPC\store\FileSystem;
|
|
||||||
use SPC\util\DependencyUtil;
|
|
||||||
|
|
||||||
abstract class BuilderBase
|
|
||||||
{
|
|
||||||
/** @var bool 是否启用 ZTS 线程安全 */
|
|
||||||
public bool $zts = false;
|
|
||||||
|
|
||||||
/** @var string 编译目标架构 */
|
|
||||||
public string $arch;
|
|
||||||
|
|
||||||
/** @var string GNU 格式的编译目标架构 */
|
|
||||||
public string $gnu_arch;
|
|
||||||
|
|
||||||
/** @var int 编译进程数 */
|
|
||||||
public int $concurrency = 1;
|
|
||||||
|
|
||||||
/** @var array<string, LibraryBase> 要编译的 libs 列表 */
|
|
||||||
protected array $libs = [];
|
|
||||||
|
|
||||||
/** @var array<string, Extension> 要编译的扩展列表 */
|
|
||||||
protected array $exts = [];
|
|
||||||
|
|
||||||
/** @var array<int, string> 要编译的扩展列表(仅名字列表,用于最后生成编译的扩展列表给 micro) */
|
|
||||||
protected array $plain_extensions = [];
|
|
||||||
|
|
||||||
/** @var bool 本次编译是否只编译 libs,不编译 PHP */
|
|
||||||
protected bool $libs_only = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建指定列表的 libs
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public function buildLibs(array $libraries): void
|
|
||||||
{
|
|
||||||
// 通过扫描目录查找 lib
|
|
||||||
$support_lib_list = [];
|
|
||||||
$classes = FileSystem::getClassesPsr4(
|
|
||||||
ROOT_DIR . '/src/SPC/builder/' . osfamily2dir() . '/library',
|
|
||||||
'SPC\\builder\\' . osfamily2dir() . '\\library'
|
|
||||||
);
|
|
||||||
foreach ($classes as $class) {
|
|
||||||
if (defined($class . '::NAME') && $class::NAME !== 'unknown' && Config::getLib($class::NAME) !== null) {
|
|
||||||
$support_lib_list[$class::NAME] = $class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果传入了空,则默认检查和安置所有支持的lib,libraries为要build的,support_lib_list为支持的列表
|
|
||||||
if ($libraries === [] && $this->isLibsOnly()) {
|
|
||||||
$libraries = array_keys($support_lib_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 排序 libs,根据依赖计算一个新的列表出来
|
|
||||||
$libraries = DependencyUtil::getLibsByDeps($libraries);
|
|
||||||
|
|
||||||
// 这里筛选 libraries,比如纯静态模式排除掉ffi
|
|
||||||
if (defined('BUILD_ALL_STATIC') && BUILD_ALL_STATIC) {
|
|
||||||
$k = array_search('libffi', $libraries, true);
|
|
||||||
$k !== false && array_splice($libraries, $k, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 过滤不支持的库后添加
|
|
||||||
foreach ($libraries as $library) {
|
|
||||||
if (!isset($support_lib_list[$library])) {
|
|
||||||
throw new RuntimeException('library [' . $library . '] is in the lib.json list but not supported to compile, but in the future I will support it!');
|
|
||||||
}
|
|
||||||
$lib = new ($support_lib_list[$library])($this);
|
|
||||||
$this->addLib($lib);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 统计还没 fetch 到本地的库
|
|
||||||
$this->checkLibsSource();
|
|
||||||
|
|
||||||
// 计算依赖,经过这里的遍历,如果没有抛出异常,说明依赖符合要求,可以继续下面的
|
|
||||||
foreach ($this->libs as $lib) {
|
|
||||||
$lib->calcDependency();
|
|
||||||
}
|
|
||||||
foreach ($this->libs as $lib) {
|
|
||||||
match ($lib->tryBuild()) {
|
|
||||||
BUILD_STATUS_OK => logger()->info('lib [' . $lib::NAME . '] build success'),
|
|
||||||
BUILD_STATUS_ALREADY => logger()->notice('lib [' . $lib::NAME . '] already built'),
|
|
||||||
BUILD_STATUS_FAILED => logger()->error('lib [' . $lib::NAME . '] build failed'),
|
|
||||||
default => logger()->warning('lib [' . $lib::NAME . '] build status unknown'),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加要编译的 Lib 库
|
|
||||||
*
|
|
||||||
* @param LibraryBase $library Lib 库对象
|
|
||||||
*/
|
|
||||||
public function addLib(LibraryBase $library): void
|
|
||||||
{
|
|
||||||
$this->libs[$library::NAME] = $library;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取要编译的 Lib 库对象
|
|
||||||
*
|
|
||||||
* @param string $name 库名称
|
|
||||||
*/
|
|
||||||
public function getLib(string $name): ?LibraryBase
|
|
||||||
{
|
|
||||||
return $this->libs[$name] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加要编译的扩展
|
|
||||||
*
|
|
||||||
* @param Extension $extension 扩展对象
|
|
||||||
*/
|
|
||||||
public function addExt(Extension $extension): void
|
|
||||||
{
|
|
||||||
$this->exts[$extension->getName()] = $extension;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取要编译的扩展对象
|
|
||||||
*
|
|
||||||
* @param string $name 扩展名称
|
|
||||||
*/
|
|
||||||
public function getExt(string $name): ?Extension
|
|
||||||
{
|
|
||||||
return $this->exts[$name] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置本次 Builder 是否为仅编译库的模式
|
|
||||||
*/
|
|
||||||
public function setLibsOnly(bool $status = true): void
|
|
||||||
{
|
|
||||||
$this->libs_only = $status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检验 ext 扩展列表是否合理,并声明 Extension 对象,检查扩展的依赖
|
|
||||||
*
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function proveExts(array $extensions): void
|
|
||||||
{
|
|
||||||
foreach ($extensions as $extension) {
|
|
||||||
$ext = new Extension($extension, $this);
|
|
||||||
$this->addExt($ext);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($this->exts as $ext) {
|
|
||||||
// 检查下依赖就行了,作用是导入依赖给 Extension 对象,今后可以对库依赖进行选择性处理
|
|
||||||
$ext->checkDependency();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->plain_extensions = $extensions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 开始构建 PHP
|
|
||||||
* 构建 micro 的规则:
|
|
||||||
* - BUILD_MICRO_NONE(默认):只编译 cli
|
|
||||||
* - BUILD_MICRO_ONLY:只编译 micro
|
|
||||||
* - BUILD_MICRO_BOTH:同时编译 micro 和 cli
|
|
||||||
*
|
|
||||||
* @param int $build_micro_rule 规则
|
|
||||||
* @param bool $bloat 保留
|
|
||||||
*/
|
|
||||||
abstract public function buildPHP(int $build_micro_rule = BUILD_MICRO_NONE, bool $bloat = false);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成依赖的扩展编译启用参数
|
|
||||||
* 例如 --enable-mbstring 等
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public function makeExtensionArgs(): string
|
|
||||||
{
|
|
||||||
$ret = [];
|
|
||||||
foreach ($this->exts as $ext) {
|
|
||||||
$ret[] = $ext->getConfigureArg();
|
|
||||||
}
|
|
||||||
logger()->info('Using configure: ' . implode(' ', $ret));
|
|
||||||
return implode(' ', $ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回是否只编译 libs 的模式
|
|
||||||
*/
|
|
||||||
public function isLibsOnly(): bool
|
|
||||||
{
|
|
||||||
return $this->libs_only;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查是否存在 lib 库对应的源码,如果不存在,则抛出异常
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
protected function checkLibsSource(): void
|
|
||||||
{
|
|
||||||
$not_downloaded = [];
|
|
||||||
foreach ($this->libs as $lib) {
|
|
||||||
if (!file_exists($lib->getSourceDir())) {
|
|
||||||
$not_downloaded[] = $lib::NAME;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($not_downloaded !== []) {
|
|
||||||
throw new RuntimeException(
|
|
||||||
'"' . implode(', ', $not_downloaded) .
|
|
||||||
'" totally ' . count($not_downloaded) .
|
|
||||||
' source' . (count($not_downloaded) === 1 ? '' : 's') .
|
|
||||||
' not downloaded, maybe you need to "fetch" ' . (count($not_downloaded) === 1 ? 'it' : 'them') . ' first?'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder;
|
|
||||||
|
|
||||||
use SPC\builder\linux\LinuxBuilder;
|
|
||||||
use SPC\builder\macos\MacOSBuilder;
|
|
||||||
use SPC\builder\windows\WindowsBuilder;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用于生成对应系统环境的 Builder 对象的类
|
|
||||||
*/
|
|
||||||
class BuilderProvider
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function makeBuilderByInput(InputInterface $input): BuilderBase
|
|
||||||
{
|
|
||||||
return match (PHP_OS_FAMILY) {
|
|
||||||
// 'Windows' => new WindowsBuilder(
|
|
||||||
// binary_sdk_dir: $input->getOption('with-sdk-binary-dir'),
|
|
||||||
// vs_ver: $input->getOption('vs-ver'),
|
|
||||||
// arch: $input->getOption('arch'),
|
|
||||||
// ),
|
|
||||||
'Darwin' => new MacOSBuilder(
|
|
||||||
cc: $input->getOption('cc'),
|
|
||||||
cxx: $input->getOption('cxx'),
|
|
||||||
arch: $input->getOption('arch'),
|
|
||||||
),
|
|
||||||
'Linux' => new LinuxBuilder(
|
|
||||||
cc: $input->getOption('cc'),
|
|
||||||
cxx: $input->getOption('cxx'),
|
|
||||||
arch: $input->getOption('arch'),
|
|
||||||
),
|
|
||||||
default => throw new RuntimeException('Current OS "' . PHP_OS_FAMILY . '" is not supported yet'),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,314 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder;
|
|
||||||
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\store\Config;
|
|
||||||
|
|
||||||
class Extension
|
|
||||||
{
|
|
||||||
protected array $dependencies = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public function __construct(protected string $name, protected BuilderBase $builder)
|
|
||||||
{
|
|
||||||
$ext_type = Config::getExt($this->name, 'type');
|
|
||||||
$unix_only = Config::getExt($this->name, 'unix-only', false);
|
|
||||||
$windows_only = Config::getExt($this->name, 'windows-only', false);
|
|
||||||
if (PHP_OS_FAMILY !== 'Windows' && $windows_only) {
|
|
||||||
throw new RuntimeException("{$ext_type} extension {$name} is not supported on Linux and macOS platform");
|
|
||||||
}
|
|
||||||
if (PHP_OS_FAMILY === 'Windows' && $unix_only) {
|
|
||||||
throw new RuntimeException("{$ext_type} extension {$name} is not supported on Windows platform");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取开启该扩展的 PHP 编译添加的参数
|
|
||||||
*
|
|
||||||
* @throws FileSystemException|RuntimeException
|
|
||||||
*/
|
|
||||||
public function getConfigureArg(): string
|
|
||||||
{
|
|
||||||
$arg = $this->getEnableArg();
|
|
||||||
switch (PHP_OS_FAMILY) {
|
|
||||||
case 'Windows':
|
|
||||||
$arg .= $this->getWindowsConfigureArg();
|
|
||||||
break;
|
|
||||||
case 'Darwin':
|
|
||||||
case 'Linux':
|
|
||||||
$arg .= $this->getUnixConfigureArg();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return $arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据 ext 的 arg-type 获取对应开启的参数,一般都是 --enable-xxx 和 --with-xxx
|
|
||||||
*
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function getEnableArg(): string
|
|
||||||
{
|
|
||||||
$_name = str_replace('_', '-', $this->name);
|
|
||||||
return match ($arg_type = Config::getExt($this->name, 'arg-type', 'enable')) {
|
|
||||||
'enable' => '--enable-' . $_name,
|
|
||||||
'with' => '--with-' . $_name,
|
|
||||||
'none', 'custom' => '',
|
|
||||||
default => throw new RuntimeException("argType does not accept {$arg_type}, use [enable/with] ."),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导出当前扩展依赖的所有 lib 库生成的 .a 静态编译库文件,以字符串形式导出,用空格分割
|
|
||||||
*/
|
|
||||||
public function getLibFilesString(): string
|
|
||||||
{
|
|
||||||
$ret = array_map(
|
|
||||||
fn ($x) => $x->getStaticLibFiles(),
|
|
||||||
$this->getLibraryDependencies(recursive: true)
|
|
||||||
);
|
|
||||||
return implode(' ', $ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查下依赖就行了,作用是导入依赖给 Extension 对象,今后可以对库依赖进行选择性处理
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public function checkDependency(): static
|
|
||||||
{
|
|
||||||
foreach (Config::getExt($this->name, 'lib-depends', []) as $name) {
|
|
||||||
$this->addLibraryDependency($name);
|
|
||||||
}
|
|
||||||
foreach (Config::getExt($this->name, 'lib-suggests', []) as $name) {
|
|
||||||
$this->addLibraryDependency($name, true);
|
|
||||||
}
|
|
||||||
foreach (Config::getExt($this->name, 'ext-depends', []) as $name) {
|
|
||||||
$this->addExtensionDependency($name);
|
|
||||||
}
|
|
||||||
foreach (Config::getExt($this->name, 'ext-suggests', []) as $name) {
|
|
||||||
$this->addExtensionDependency($name, true);
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getExtensionDependency(): array
|
|
||||||
{
|
|
||||||
return array_filter($this->dependencies, fn ($x) => $x instanceof Extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getName(): string
|
|
||||||
{
|
|
||||||
return $this->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
protected function addLibraryDependency(string $name, bool $optional = false): void
|
|
||||||
{
|
|
||||||
$depLib = $this->builder->getLib($name);
|
|
||||||
if (!$depLib) {
|
|
||||||
if (!$optional) {
|
|
||||||
throw new RuntimeException("extension {$this->name} requires library {$name}");
|
|
||||||
}
|
|
||||||
logger()->info("enabling {$this->name} without library {$name}");
|
|
||||||
} else {
|
|
||||||
$this->dependencies[] = $depLib;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
protected function addExtensionDependency(string $name, bool $optional = false): void
|
|
||||||
{
|
|
||||||
$depExt = $this->builder->getExt($name);
|
|
||||||
if (!$depExt) {
|
|
||||||
if (!$optional) {
|
|
||||||
throw new RuntimeException("{$this->name} requires extension {$name}");
|
|
||||||
}
|
|
||||||
logger()->info("enabling {$this->name} without extension {$name}");
|
|
||||||
} else {
|
|
||||||
$this->dependencies[] = $depExt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getWindowsConfigureArg(): string
|
|
||||||
{
|
|
||||||
$arg = '';
|
|
||||||
switch ($this->name) {
|
|
||||||
case 'redis':
|
|
||||||
// $arg = '--enable-redis';
|
|
||||||
// if ($this->builder->getLib('zstd')) {
|
|
||||||
// $arg .= ' --enable-redis-zstd --with-libzstd ';
|
|
||||||
// }
|
|
||||||
break;
|
|
||||||
case 'xml':
|
|
||||||
case 'soap':
|
|
||||||
case 'xmlreader':
|
|
||||||
case 'xmlwriter':
|
|
||||||
case 'dom':
|
|
||||||
$arg .= ' --with-libxml ';
|
|
||||||
break;
|
|
||||||
case 'swow':
|
|
||||||
if ($this->builder->getLib('openssl')) {
|
|
||||||
$arg .= ' --enable-swow-ssl';
|
|
||||||
}
|
|
||||||
if ($this->builder->getLib('curl')) {
|
|
||||||
$arg .= ' --enable-swow-curl';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return $arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getUnixConfigureArg(): string
|
|
||||||
{
|
|
||||||
$arg = '';
|
|
||||||
switch ($this->name) {
|
|
||||||
/*case 'event':
|
|
||||||
$arg = ' --with-event-core --with-event-libevent-dir="' . BUILD_ROOT_PATH . '"';
|
|
||||||
if ($this->builder->getLib('openssl')) {
|
|
||||||
$arg .= ' --with-event-openssl --with-openssl-dir="' . BUILD_ROOT_PATH . '"';
|
|
||||||
}
|
|
||||||
break;*/
|
|
||||||
case 'mbstring':
|
|
||||||
$arg = ' --disable-mbregex ONIG_CFLAGS=-I"' . BUILD_ROOT_PATH . '" ' .
|
|
||||||
'ONIG_LIBS="' . $this->getLibFilesString() . '" ';
|
|
||||||
break;
|
|
||||||
case 'gmp':
|
|
||||||
$arg = ' --with-gmp="' . BUILD_ROOT_PATH . '" ';
|
|
||||||
break;
|
|
||||||
case 'sqlite3':
|
|
||||||
$arg = ' --with-sqlite3="' . BUILD_ROOT_PATH . '" ' .
|
|
||||||
'SQLITE_CFLAGS=-I"' . BUILD_INCLUDE_PATH . '" ' .
|
|
||||||
'SQLITE_LIBS="' . $this->getLibFilesString() . '" ';
|
|
||||||
break;
|
|
||||||
case 'redis':
|
|
||||||
$arg = ' --enable-redis --disable-redis-session';
|
|
||||||
if ($this->builder->getLib('zstd')) {
|
|
||||||
$arg .= ' --enable-redis-zstd --with-libzstd="' . BUILD_ROOT_PATH . '" ';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'yaml':
|
|
||||||
$arg .= ' --with-yaml="' . BUILD_ROOT_PATH . '" ';
|
|
||||||
break;
|
|
||||||
case 'zstd':
|
|
||||||
$arg .= ' --with-libzstd';
|
|
||||||
break;
|
|
||||||
case 'bz2':
|
|
||||||
$arg = ' --with-bz2="' . BUILD_ROOT_PATH . '" ';
|
|
||||||
break;
|
|
||||||
case 'openssl':
|
|
||||||
$arg .= ' ' .
|
|
||||||
'OPENSSL_CFLAGS=-I"' . BUILD_INCLUDE_PATH . '" ' .
|
|
||||||
'OPENSSL_LIBS="' . $this->getLibFilesString() . '" ';
|
|
||||||
break;
|
|
||||||
case 'curl':
|
|
||||||
$arg .= ' ' .
|
|
||||||
'CURL_CFLAGS=-I"' . BUILD_INCLUDE_PATH . '" ' .
|
|
||||||
'CURL_LIBS="' . $this->getLibFilesString() . '" ';
|
|
||||||
break;
|
|
||||||
case 'gd':
|
|
||||||
if ($this->builder->getLib('freetype')) {
|
|
||||||
$arg .= ' --with-freetype ' .
|
|
||||||
'FREETYPE2_CFLAGS=-I"' . BUILD_INCLUDE_PATH . '/freetype2" ' .
|
|
||||||
'FREETYPE2_LIBS="' . $this->getLibFilesString() . '" ';
|
|
||||||
}
|
|
||||||
$arg .= ' ' .
|
|
||||||
'PNG_CFLAGS=-I"' . BUILD_INCLUDE_PATH . '" ' .
|
|
||||||
'PNG_LIBS="' . $this->getLibFilesString() . '" ';
|
|
||||||
break;
|
|
||||||
// TODO: other libraries
|
|
||||||
case 'phar':
|
|
||||||
case 'zlib':
|
|
||||||
$arg .= ' ' .
|
|
||||||
'ZLIB_CFLAGS=-I"' . BUILD_INCLUDE_PATH . '" ' .
|
|
||||||
'ZLIB_LIBS="' . $this->getLibFilesString() . '" ';
|
|
||||||
break;
|
|
||||||
case 'xml': // xml may use expat
|
|
||||||
if ($this->getLibraryDependencies()['expat'] ?? null) {
|
|
||||||
$arg .= ' --with-expat="' . BUILD_ROOT_PATH . '" ' .
|
|
||||||
'EXPAT_CFLAGS=-I"' . BUILD_INCLUDE_PATH . '" ' .
|
|
||||||
'EXPAT_LIBS="' . $this->getLibFilesString() . '" ';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// no break
|
|
||||||
case 'soap':
|
|
||||||
case 'xmlreader':
|
|
||||||
case 'xmlwriter':
|
|
||||||
case 'dom':
|
|
||||||
$arg .= ' --with-libxml="' . BUILD_ROOT_PATH . '" ' .
|
|
||||||
'LIBXML_CFLAGS=-I"' . realpath('include/libxml2') . '" ' .
|
|
||||||
'LIBXML_LIBS="' . $this->getLibFilesString() . '" ';
|
|
||||||
break;
|
|
||||||
case 'ffi':
|
|
||||||
$arg .= ' ' .
|
|
||||||
'FFI_CFLAGS=-I"' . BUILD_INCLUDE_PATH . '" ' .
|
|
||||||
'FFI_LIBS="' . $this->getLibFilesString() . '" ';
|
|
||||||
break;
|
|
||||||
case 'zip':
|
|
||||||
$arg .= ' ' .
|
|
||||||
'LIBZIP_CFLAGS=-I"' . BUILD_INCLUDE_PATH . '" ' .
|
|
||||||
'LIBZIP_LIBS="' . $this->getLibFilesString() . '" ';
|
|
||||||
break;
|
|
||||||
case 'mbregex':
|
|
||||||
$arg .= ' ' .
|
|
||||||
'ONIG_CFLAGS=-I"' . BUILD_INCLUDE_PATH . '" ' .
|
|
||||||
'ONIG_LIBS="' . $this->getLibFilesString() . '" ';
|
|
||||||
break;
|
|
||||||
case 'swow':
|
|
||||||
$arg .= $this->builder->getLib('openssl') ? ' --enable-swow-ssl' : ' --disable-swow-ssl';
|
|
||||||
$arg .= $this->builder->getLib('curl') ? ' --enable-swow-curl' : ' --disable-swow-curl';
|
|
||||||
$arg .= ' SWOW_UV_CFLAGS=-I"' . BUILD_INCLUDE_PATH . '" ';
|
|
||||||
break;
|
|
||||||
case 'swoole':
|
|
||||||
if ($this->builder->getLib('openssl')) {
|
|
||||||
$arg .= ' --enable-openssl';
|
|
||||||
} else {
|
|
||||||
$arg .= ' --disable-openssl --without-openssl';
|
|
||||||
}
|
|
||||||
// curl hook is buggy for static php
|
|
||||||
$arg .= ' --disable-swoole-curl';
|
|
||||||
}
|
|
||||||
return $arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getLibraryDependencies(bool $recursive = false): array
|
|
||||||
{
|
|
||||||
$ret = array_filter($this->dependencies, fn ($x) => $x instanceof LibraryBase);
|
|
||||||
if (!$recursive) {
|
|
||||||
return $ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
$deps = [];
|
|
||||||
|
|
||||||
$added = 1;
|
|
||||||
while ($added !== 0) {
|
|
||||||
$added = 0;
|
|
||||||
foreach ($ret as $depName => $dep) {
|
|
||||||
foreach ($dep->getDependencies(true) as $depdepName => $depdep) {
|
|
||||||
if (!in_array($depdepName, array_keys($deps), true)) {
|
|
||||||
$deps[$depdepName] = $depdep;
|
|
||||||
++$added;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!in_array($depName, array_keys($deps), true)) {
|
|
||||||
$deps[$depName] = $dep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $deps;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder;
|
|
||||||
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\store\Config;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lib 库的基类操作对象
|
|
||||||
*/
|
|
||||||
abstract class LibraryBase
|
|
||||||
{
|
|
||||||
/** @var string lib 依赖名称,必须重写 */
|
|
||||||
public const NAME = 'unknown';
|
|
||||||
|
|
||||||
/** @var string lib 依赖的根目录 */
|
|
||||||
protected string $source_dir;
|
|
||||||
|
|
||||||
/** @var array 依赖列表 */
|
|
||||||
protected array $dependencies = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function __construct(?string $source_dir = null)
|
|
||||||
{
|
|
||||||
if (static::NAME === 'unknown') {
|
|
||||||
throw new RuntimeException('no unknown!!!!!');
|
|
||||||
}
|
|
||||||
$this->source_dir = $source_dir ?? (SOURCE_PATH . '/' . static::NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取 lib 库的根目录
|
|
||||||
*/
|
|
||||||
public function getSourceDir(): string
|
|
||||||
{
|
|
||||||
return $this->source_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前 lib 库的所有依赖列表
|
|
||||||
*
|
|
||||||
* @param bool $recursive 是否递归获取(默认为 False)
|
|
||||||
* @return array<string, LibraryBase> 依赖的 Map
|
|
||||||
*/
|
|
||||||
public function getDependencies(bool $recursive = false): array
|
|
||||||
{
|
|
||||||
// 非递归情况下直接返回通过 addLibraryDependency 方法添加的依赖
|
|
||||||
if (!$recursive) {
|
|
||||||
return $this->dependencies;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 下面为递归获取依赖列表,根据依赖顺序
|
|
||||||
$deps = [];
|
|
||||||
|
|
||||||
$added = 1;
|
|
||||||
while ($added !== 0) {
|
|
||||||
$added = 0;
|
|
||||||
foreach ($this->dependencies as $depName => $dep) {
|
|
||||||
foreach ($dep->getDependencies(true) as $depdepName => $depdep) {
|
|
||||||
if (!in_array($depdepName, array_keys($deps), true)) {
|
|
||||||
$deps[$depdepName] = $depdep;
|
|
||||||
++$added;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!in_array($depName, array_keys($deps), true)) {
|
|
||||||
$deps[$depName] = $dep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $deps;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 计算依赖列表,不符合依赖将抛出异常
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public function calcDependency(): void
|
|
||||||
{
|
|
||||||
// 先从配置文件添加依赖,这里根据不同的操作系统分别选择不同的元信息
|
|
||||||
/*
|
|
||||||
选择规则:
|
|
||||||
如果是 Windows 系统,则依次尝试有无 lib-depends-windows、lib-depends-win、lib-depends。
|
|
||||||
如果是 macOS 系统,则依次尝试 lib-depends-darwin、lib-depends-unix、lib-depends。
|
|
||||||
如果是 Linux 系统,则依次尝试 lib-depends-linux、lib-depends-unix、lib-depends。
|
|
||||||
*/
|
|
||||||
foreach (Config::getLib(static::NAME, 'lib-depends', []) as $dep_name) {
|
|
||||||
$this->addLibraryDependency($dep_name);
|
|
||||||
}
|
|
||||||
foreach (Config::getLib(static::NAME, 'lib-suggests', []) as $dep_name) {
|
|
||||||
$this->addLibraryDependency($dep_name, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前库编译出来获取到的静态库文件列表
|
|
||||||
*
|
|
||||||
* @return string[] 获取编译出来后的需要的静态库文件列表
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function getStaticLibs(): array
|
|
||||||
{
|
|
||||||
return Config::getLib(static::NAME, 'static-libs', []);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前 lib 编译出来的 C Header 文件列表
|
|
||||||
*
|
|
||||||
* @return string[] 获取编译出来后需要的 C Header 文件列表
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function getHeaders(): array
|
|
||||||
{
|
|
||||||
return Config::getLib(static::NAME, 'headers', []);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 证明该库是否已编译好且就绪,如果没有就绪,内部会调用 build 来进行构建该库
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public function tryBuild(bool $force_build = false): int
|
|
||||||
{
|
|
||||||
// 传入 true,表明直接编译
|
|
||||||
if ($force_build) {
|
|
||||||
logger()->info('Building required library ' . static::NAME);
|
|
||||||
$this->build();
|
|
||||||
return BUILD_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 看看这些库是不是存在,如果不存在,则调用编译并返回结果状态
|
|
||||||
foreach ($this->getStaticLibs() as $name) {
|
|
||||||
if (!file_exists(BUILD_LIB_PATH . "/{$name}")) {
|
|
||||||
$this->tryBuild(true);
|
|
||||||
return BUILD_STATUS_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 头文件同理
|
|
||||||
foreach ($this->getHeaders() as $name) {
|
|
||||||
if (!file_exists(BUILD_INCLUDE_PATH . "/{$name}")) {
|
|
||||||
$this->tryBuild(true);
|
|
||||||
return BUILD_STATUS_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 到这里说明所有的文件都存在,就跳过编译
|
|
||||||
return BUILD_STATUS_ALREADY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取构建当前 lib 的 Builder 对象
|
|
||||||
*/
|
|
||||||
abstract public function getBuilder(): BuilderBase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建该库需要调用的命令和操作
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
abstract protected function build();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加 lib 库的依赖库
|
|
||||||
*
|
|
||||||
* @param string $name 依赖名称
|
|
||||||
* @param bool $optional 是否是可选依赖(默认为 False)
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
protected function addLibraryDependency(string $name, bool $optional = false): void
|
|
||||||
{
|
|
||||||
// Log::i("add $name as dep of {$this->name}");
|
|
||||||
$dep_lib = $this->getBuilder()->getLib($name);
|
|
||||||
if (!$dep_lib) {
|
|
||||||
if (!$optional) {
|
|
||||||
throw new RuntimeException(static::NAME . " requires library {$name}");
|
|
||||||
}
|
|
||||||
logger()->debug('enabling ' . static::NAME . " without {$name}");
|
|
||||||
} else {
|
|
||||||
$this->dependencies[$name] = $dep_lib;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder;
|
|
||||||
|
|
||||||
interface LibraryInterface
|
|
||||||
{
|
|
||||||
public function getName(): string;
|
|
||||||
}
|
|
||||||
@@ -1,310 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux;
|
|
||||||
|
|
||||||
use SPC\builder\BuilderBase;
|
|
||||||
use SPC\builder\linux\library\LinuxLibraryBase;
|
|
||||||
use SPC\builder\traits\UnixBuilderTrait;
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\util\Patcher;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Linux 系统环境下的构建器
|
|
||||||
*/
|
|
||||||
class LinuxBuilder extends BuilderBase
|
|
||||||
{
|
|
||||||
/** 编译的 Unix 工具集 */
|
|
||||||
use UnixBuilderTrait;
|
|
||||||
|
|
||||||
/** @var string[] Linux 环境下编译依赖的命令 */
|
|
||||||
public const REQUIRED_COMMANDS = ['make', 'bison', 'flex', 'pkg-config', 'git', 'autoconf', 'automake', 'tar', 'unzip', /* 'xz', 好像不需要 */ 'gzip', 'bzip2', 'cmake'];
|
|
||||||
|
|
||||||
/** @var string 使用的 libc */
|
|
||||||
public string $libc;
|
|
||||||
|
|
||||||
/** @var array 特殊架构下的 cflags */
|
|
||||||
public array $tune_c_flags;
|
|
||||||
|
|
||||||
/** @var string pkg-config 环境变量 */
|
|
||||||
public string $pkgconf_env;
|
|
||||||
|
|
||||||
/** @var string 交叉编译变量 */
|
|
||||||
public string $cross_compile_prefix = '';
|
|
||||||
|
|
||||||
public string $note_section = "Je pense, donc je suis\0";
|
|
||||||
|
|
||||||
private bool $phar_patched = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function __construct(?string $cc = null, ?string $cxx = null, ?string $arch = null)
|
|
||||||
{
|
|
||||||
// 初始化一些默认参数
|
|
||||||
$this->cc = $cc ?? 'musl-gcc';
|
|
||||||
$this->cxx = $cxx ?? 'g++';
|
|
||||||
$this->arch = $arch ?? php_uname('m');
|
|
||||||
$this->gnu_arch = arch2gnu($this->arch);
|
|
||||||
$this->libc = 'musl'; // SystemUtil::selectLibc($this->cc);
|
|
||||||
|
|
||||||
// 根据 CPU 线程数设置编译进程数
|
|
||||||
$this->concurrency = SystemUtil::getCpuCount();
|
|
||||||
// 设置 cflags
|
|
||||||
$this->arch_c_flags = SystemUtil::getArchCFlags($this->cc, $this->arch);
|
|
||||||
$this->arch_cxx_flags = SystemUtil::getArchCFlags($this->cxx, $this->arch);
|
|
||||||
$this->tune_c_flags = SystemUtil::checkCCFlags(SystemUtil::getTuneCFlags($this->arch), $this->cc);
|
|
||||||
// 设置 cmake
|
|
||||||
$this->cmake_toolchain_file = SystemUtil::makeCmakeToolchainFile(
|
|
||||||
os: 'Linux',
|
|
||||||
target_arch: $this->arch,
|
|
||||||
cflags: $this->arch_c_flags,
|
|
||||||
cc: $this->cc,
|
|
||||||
cxx: $this->cxx
|
|
||||||
);
|
|
||||||
// 设置 pkgconfig
|
|
||||||
$this->pkgconf_env = 'PKG_CONFIG_PATH="' . BUILD_LIB_PATH . '/pkgconfig"';
|
|
||||||
// 设置 configure 依赖的环境变量
|
|
||||||
$this->configure_env =
|
|
||||||
$this->pkgconf_env . ' ' .
|
|
||||||
"CC='{$this->cc}' " .
|
|
||||||
"CXX='{$this->cxx}' " .
|
|
||||||
(php_uname('m') === $this->arch ? '' : "CFLAGS='{$this->arch_c_flags}'");
|
|
||||||
// 交叉编译依赖的,TODO
|
|
||||||
if (php_uname('m') !== $this->arch) {
|
|
||||||
$this->cross_compile_prefix = SystemUtil::getCrossCompilePrefix($this->cc, $this->arch);
|
|
||||||
logger()->info('using cross compile prefix: ' . $this->cross_compile_prefix);
|
|
||||||
$this->configure_env .= " CROSS_COMPILE='{$this->cross_compile_prefix}'";
|
|
||||||
}
|
|
||||||
|
|
||||||
$missing = [];
|
|
||||||
foreach (self::REQUIRED_COMMANDS as $cmd) {
|
|
||||||
if (SystemUtil::findCommand($cmd) === null) {
|
|
||||||
$missing[] = $cmd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!empty($missing)) {
|
|
||||||
throw new RuntimeException('missing system commands: ' . implode(', ', $missing));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创立 pkg-config 和放头文件的目录
|
|
||||||
f_mkdir(BUILD_LIB_PATH . '/pkgconfig', recursive: true);
|
|
||||||
f_mkdir(BUILD_INCLUDE_PATH, recursive: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function makeAutoconfArgs(string $name, array $libSpecs): string
|
|
||||||
{
|
|
||||||
$ret = '';
|
|
||||||
foreach ($libSpecs as $libName => $arr) {
|
|
||||||
$lib = $this->getLib($libName);
|
|
||||||
|
|
||||||
$arr = $arr ?? [];
|
|
||||||
|
|
||||||
$disableArgs = $arr[0] ?? null;
|
|
||||||
$prefix = $arr[1] ?? null;
|
|
||||||
if ($lib instanceof LinuxLibraryBase) {
|
|
||||||
logger()->info("{$name} \033[32;1mwith\033[0;1m {$libName} support");
|
|
||||||
$ret .= $lib->makeAutoconfEnv($prefix) . ' ';
|
|
||||||
} else {
|
|
||||||
logger()->info("{$name} \033[31;1mwithout\033[0;1m {$libName} support");
|
|
||||||
$ret .= ($disableArgs ?? "--with-{$libName}=no") . ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rtrim($ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public function buildPHP(int $build_micro_rule = BUILD_MICRO_NONE, bool $with_clean = false, bool $bloat = false)
|
|
||||||
{
|
|
||||||
if (!$bloat) {
|
|
||||||
$extra_libs = implode(' ', $this->getAllStaticLibFiles());
|
|
||||||
} else {
|
|
||||||
logger()->info('bloat linking');
|
|
||||||
$extra_libs = implode(
|
|
||||||
' ',
|
|
||||||
array_map(
|
|
||||||
fn ($x) => "-Xcompiler {$x}",
|
|
||||||
array_filter($this->getAllStaticLibFiles())
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$envs = $this->pkgconf_env . ' ' .
|
|
||||||
"CC='{$this->cc}' " .
|
|
||||||
"CXX='{$this->cxx}' ";
|
|
||||||
$cflags = $this->arch_c_flags;
|
|
||||||
$use_lld = '';
|
|
||||||
|
|
||||||
switch ($this->libc) {
|
|
||||||
case 'musl_wrapper':
|
|
||||||
case 'glibc':
|
|
||||||
$cflags .= ' -static-libgcc -I"' . BUILD_INCLUDE_PATH . '"';
|
|
||||||
break;
|
|
||||||
case 'musl':
|
|
||||||
if (str_ends_with($this->cc, 'clang') && SystemUtil::findCommand('lld')) {
|
|
||||||
$use_lld = '-Xcompiler -fuse-ld=lld';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new RuntimeException('libc ' . $this->libc . ' is not implemented yet');
|
|
||||||
}
|
|
||||||
|
|
||||||
$envs = "{$envs} CFLAGS='{$cflags}' LIBS='-ldl -lpthread'";
|
|
||||||
|
|
||||||
Patcher::patchPHPBeforeConfigure($this);
|
|
||||||
|
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')->exec('./buildconf --force');
|
|
||||||
|
|
||||||
Patcher::patchPHPConfigure($this);
|
|
||||||
|
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')
|
|
||||||
->exec(
|
|
||||||
'./configure ' .
|
|
||||||
'--prefix= ' .
|
|
||||||
'--with-valgrind=no ' .
|
|
||||||
'--enable-shared=no ' .
|
|
||||||
'--enable-static=yes ' .
|
|
||||||
"--host={$this->gnu_arch}-unknown-linux " .
|
|
||||||
'--disable-all ' .
|
|
||||||
'--disable-cgi ' .
|
|
||||||
'--disable-phpdbg ' .
|
|
||||||
'--enable-cli ' .
|
|
||||||
'--enable-micro=all-static ' .
|
|
||||||
($this->zts ? '--enable-zts' : '') . ' ' .
|
|
||||||
$this->makeExtensionArgs() . ' ' .
|
|
||||||
$envs
|
|
||||||
);
|
|
||||||
|
|
||||||
$extra_libs .= $this->generateExtraLibs();
|
|
||||||
|
|
||||||
file_put_contents('/tmp/comment', $this->note_section);
|
|
||||||
|
|
||||||
// 清理
|
|
||||||
$this->cleanMake();
|
|
||||||
|
|
||||||
if ($bloat) {
|
|
||||||
logger()->info('bloat linking');
|
|
||||||
$extra_libs = "-Wl,--whole-archive {$extra_libs} -Wl,--no-whole-archive";
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($build_micro_rule) {
|
|
||||||
case BUILD_MICRO_NONE:
|
|
||||||
logger()->info('building cli');
|
|
||||||
$this->buildCli($extra_libs, $use_lld);
|
|
||||||
break;
|
|
||||||
case BUILD_MICRO_ONLY:
|
|
||||||
logger()->info('building micro');
|
|
||||||
$this->buildMicro($extra_libs, $use_lld, $cflags);
|
|
||||||
break;
|
|
||||||
case BUILD_MICRO_BOTH:
|
|
||||||
logger()->info('building cli and micro');
|
|
||||||
$this->buildCli($extra_libs, $use_lld);
|
|
||||||
$this->buildMicro($extra_libs, $use_lld, $cflags);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (php_uname('m') === $this->arch) {
|
|
||||||
$this->sanityCheck($build_micro_rule);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->phar_patched) {
|
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')->exec('patch -p1 -R < sapi/micro/patches/phar.patch');
|
|
||||||
}
|
|
||||||
|
|
||||||
file_put_contents(SOURCE_PATH . '/php-src/.extensions.json', json_encode($this->plain_extensions, JSON_PRETTY_PRINT));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function buildCli(string $extra_libs, string $use_lld): void
|
|
||||||
{
|
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')
|
|
||||||
->exec('sed -i "s|//lib|/lib|g" Makefile')
|
|
||||||
->exec(
|
|
||||||
'make -j' . $this->concurrency .
|
|
||||||
' EXTRA_CFLAGS="-g -Os -fno-ident ' . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags)) . '" ' .
|
|
||||||
"EXTRA_LIBS=\"{$extra_libs}\" " .
|
|
||||||
"EXTRA_LDFLAGS_PROGRAM='{$use_lld} -all-static' " .
|
|
||||||
'cli'
|
|
||||||
);
|
|
||||||
|
|
||||||
shell()->cd(SOURCE_PATH . '/php-src/sapi/cli')
|
|
||||||
->exec("{$this->cross_compile_prefix}objcopy --only-keep-debug php php.debug")
|
|
||||||
->exec('elfedit --output-osabi linux php')
|
|
||||||
->exec("{$this->cross_compile_prefix}strip --strip-all php")
|
|
||||||
->exec("{$this->cross_compile_prefix}objcopy --update-section .comment=/tmp/comment --add-gnu-debuglink=php.debug --remove-section=.note php");
|
|
||||||
$this->deployBinary(BUILD_TYPE_CLI);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function buildMicro(string $extra_libs, string $use_lld, string $cflags): void
|
|
||||||
{
|
|
||||||
if ($this->getExt('phar')) {
|
|
||||||
$this->phar_patched = true;
|
|
||||||
try {
|
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')->exec('patch -p1 < sapi/micro/patches/phar.patch');
|
|
||||||
} catch (RuntimeException $e) {
|
|
||||||
logger()->error('failed to patch phat due to patch exit with code ' . $e->getCode());
|
|
||||||
$this->phar_patched = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')
|
|
||||||
->exec('sed -i "s|//lib|/lib|g" Makefile')
|
|
||||||
->exec(
|
|
||||||
"make -j{$this->concurrency} " .
|
|
||||||
'EXTRA_CFLAGS=' . quote('-g -Os -fno-ident ' . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags))) . ' ' .
|
|
||||||
'EXTRA_LIBS=' . quote($extra_libs) . ' ' .
|
|
||||||
'EXTRA_LDFLAGS_PROGRAM=' . quote("{$cflags} {$use_lld}" . ' -all-static', "'") . ' ' .
|
|
||||||
'micro'
|
|
||||||
);
|
|
||||||
|
|
||||||
shell()->cd(SOURCE_PATH . '/php-src/sapi/micro')->exec("{$this->cross_compile_prefix}strip --strip-all micro.sfx");
|
|
||||||
|
|
||||||
$this->deployBinary(BUILD_TYPE_MICRO);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
private function generateExtraLibs(): string
|
|
||||||
{
|
|
||||||
if ($this->libc === 'glibc') {
|
|
||||||
$glibc_libs = [
|
|
||||||
'rt',
|
|
||||||
'm',
|
|
||||||
'c',
|
|
||||||
'pthread',
|
|
||||||
'dl',
|
|
||||||
'nsl',
|
|
||||||
'anl',
|
|
||||||
// 'crypt',
|
|
||||||
'resolv',
|
|
||||||
'util',
|
|
||||||
];
|
|
||||||
$makefile = file_get_contents(SOURCE_PATH . '/php-src/Makefile');
|
|
||||||
preg_match('/^EXTRA_LIBS\s*=\s*(.*)$/m', $makefile, $matches);
|
|
||||||
if (!$matches) {
|
|
||||||
throw new RuntimeException('failed to find EXTRA_LIBS in Makefile');
|
|
||||||
}
|
|
||||||
$_extra_libs = [];
|
|
||||||
foreach (array_filter(explode(' ', $matches[1])) as $used) {
|
|
||||||
foreach ($glibc_libs as $libName) {
|
|
||||||
if ("-l{$libName}" === $used && !in_array("-l{$libName}", $_extra_libs, true)) {
|
|
||||||
array_unshift($_extra_libs, "-l{$libName}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ' ' . implode(' ', $_extra_libs);
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,240 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux;
|
|
||||||
|
|
||||||
use JetBrains\PhpStorm\ArrayShape;
|
|
||||||
use SPC\builder\traits\UnixSystemUtilTrait;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class SystemUtil
|
|
||||||
{
|
|
||||||
use UnixSystemUtilTrait;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查找并选择编译器命令
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function selectCC(): string
|
|
||||||
{
|
|
||||||
logger()->debug('Choose cc');
|
|
||||||
if (self::findCommand('clang')) {
|
|
||||||
logger()->info('using clang');
|
|
||||||
return 'clang';
|
|
||||||
}
|
|
||||||
if (self::findCommand('gcc')) {
|
|
||||||
logger()->info('using gcc');
|
|
||||||
return 'gcc';
|
|
||||||
}
|
|
||||||
throw new RuntimeException('no supported cc found');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查找并选择编译器命令
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function selectCXX(): string
|
|
||||||
{
|
|
||||||
logger()->debug('Choose cxx');
|
|
||||||
if (self::findCommand('clang++')) {
|
|
||||||
logger()->info('using clang++');
|
|
||||||
return 'clang++';
|
|
||||||
}
|
|
||||||
if (self::findCommand('g++')) {
|
|
||||||
logger()->info('using g++');
|
|
||||||
return 'g++';
|
|
||||||
}
|
|
||||||
return self::selectCC();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ArrayShape(['dist' => 'mixed|string', 'ver' => 'mixed|string'])]
|
|
||||||
public static function getOSRelease(): array
|
|
||||||
{
|
|
||||||
$ret = [
|
|
||||||
'dist' => 'unknown',
|
|
||||||
'ver' => 'unknown',
|
|
||||||
];
|
|
||||||
switch (true) {
|
|
||||||
case file_exists('/etc/os-release'):
|
|
||||||
$lines = file('/etc/os-release');
|
|
||||||
foreach ($lines as $line) {
|
|
||||||
if (preg_match('/^ID=(.*)$/', $line, $matches)) {
|
|
||||||
$ret['dist'] = $matches[1];
|
|
||||||
}
|
|
||||||
if (preg_match('/^VERSION_ID=(.*)$/', $line, $matches)) {
|
|
||||||
$ret['ver'] = $matches[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$ret['dist'] = trim($ret['dist'], '"\'');
|
|
||||||
$ret['ver'] = trim($ret['ver'], '"\'');
|
|
||||||
if (strcasecmp($ret['dist'], 'centos') === 0) {
|
|
||||||
$ret['dist'] = 'redhat';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case file_exists('/etc/centos-release'):
|
|
||||||
$lines = file('/etc/centos-release');
|
|
||||||
goto rh;
|
|
||||||
case file_exists('/etc/redhat-release'):
|
|
||||||
$lines = file('/etc/redhat-release');
|
|
||||||
rh:
|
|
||||||
foreach ($lines as $line) {
|
|
||||||
if (preg_match('/release\s+(\d+(\.\d+)*)/', $line, $matches)) {
|
|
||||||
$ret['dist'] = 'redhat';
|
|
||||||
$ret['ver'] = $matches[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return $ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getCpuCount(): int
|
|
||||||
{
|
|
||||||
$ncpu = 1;
|
|
||||||
|
|
||||||
if (is_file('/proc/cpuinfo')) {
|
|
||||||
$cpuinfo = file_get_contents('/proc/cpuinfo');
|
|
||||||
preg_match_all('/^processor/m', $cpuinfo, $matches);
|
|
||||||
$ncpu = count($matches[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $ncpu;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function getCCType(string $cc): string
|
|
||||||
{
|
|
||||||
return match (true) {
|
|
||||||
str_ends_with($cc, 'c++'), str_ends_with($cc, 'cc'), str_ends_with($cc, 'g++'), str_ends_with($cc, 'gcc') => 'gcc',
|
|
||||||
$cc === 'clang++', $cc === 'clang', str_starts_with($cc, 'musl-clang') => 'clang',
|
|
||||||
default => throw new RuntimeException("unknown cc type: {$cc}"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function getArchCFlags(string $cc, string $arch): string
|
|
||||||
{
|
|
||||||
if (php_uname('m') === $arch) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
return match (static::getCCType($cc)) {
|
|
||||||
'clang' => match ($arch) {
|
|
||||||
'x86_64' => '--target=x86_64-unknown-linux',
|
|
||||||
'arm64', 'aarch64' => '--target=arm64-unknown-linux',
|
|
||||||
default => throw new RuntimeException('unsupported arch: ' . $arch),
|
|
||||||
},
|
|
||||||
'gcc' => '',
|
|
||||||
default => throw new RuntimeException('cc compiler ' . $cc . ' is not supported'),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function getTuneCFlags(string $arch): array
|
|
||||||
{
|
|
||||||
return match ($arch) {
|
|
||||||
'x86_64' => [
|
|
||||||
'-march=corei7',
|
|
||||||
'-mtune=core-avx2',
|
|
||||||
],
|
|
||||||
'arm64', 'aarch64' => [],
|
|
||||||
default => throw new RuntimeException('unsupported arch: ' . $arch),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function checkCCFlags(array $flags, string $cc): array
|
|
||||||
{
|
|
||||||
return array_filter($flags, fn ($flag) => static::checkCCFlag($flag, $cc));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function checkCCFlag(string $flag, string $cc): string
|
|
||||||
{
|
|
||||||
[$ret] = shell()->execWithResult("echo | {$cc} -E -x c - {$flag}");
|
|
||||||
if ($ret != 0) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
return $flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function getCrossCompilePrefix(string $cc, string $arch): string
|
|
||||||
{
|
|
||||||
return match (static::getCCType($cc)) {
|
|
||||||
// guessing clang toolchains
|
|
||||||
'clang' => match ($arch) {
|
|
||||||
'x86_64' => 'x86_64-linux-gnu-',
|
|
||||||
'arm64', 'aarch64' => 'aarch64-linux-gnu-',
|
|
||||||
default => throw new RuntimeException('unsupported arch: ' . $arch),
|
|
||||||
},
|
|
||||||
// remove gcc postfix
|
|
||||||
'gcc' => str_replace('-cc', '', str_replace('-gcc', '', $cc)) . '-',
|
|
||||||
default => throw new RuntimeException('unsupported cc'),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function findStaticLib(string $name): ?array
|
|
||||||
{
|
|
||||||
$paths = getenv('LIBPATH');
|
|
||||||
if (!$paths) {
|
|
||||||
$paths = '/lib:/lib64:/usr/lib:/usr/lib64:/usr/local/lib:/usr/local/lib64';
|
|
||||||
}
|
|
||||||
foreach (explode(':', $paths) as $path) {
|
|
||||||
if (file_exists("{$path}/{$name}")) {
|
|
||||||
return ["{$path}", "{$name}"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function findStaticLibs(array $names): ?array
|
|
||||||
{
|
|
||||||
$ret = [];
|
|
||||||
foreach ($names as $name) {
|
|
||||||
$path = static::findStaticLib($name);
|
|
||||||
if (!$path) {
|
|
||||||
logger()->warning("static library {$name} not found");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$ret[] = $path;
|
|
||||||
}
|
|
||||||
return $ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function findHeader(string $name): ?array
|
|
||||||
{
|
|
||||||
$paths = getenv('INCLUDEPATH');
|
|
||||||
if (!$paths) {
|
|
||||||
$paths = '/include:/usr/include:/usr/local/include';
|
|
||||||
}
|
|
||||||
foreach (explode(':', $paths) as $path) {
|
|
||||||
if (file_exists("{$path}/{$name}") || is_dir("{$path}/{$name}")) {
|
|
||||||
return ["{$path}", "{$name}"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function findHeaders(array $names): ?array
|
|
||||||
{
|
|
||||||
$ret = [];
|
|
||||||
foreach ($names as $name) {
|
|
||||||
$path = static::findHeader($name);
|
|
||||||
if (!$path) {
|
|
||||||
logger()->warning("header {$name} not found");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$ret[] = $path;
|
|
||||||
}
|
|
||||||
return $ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
use SPC\builder\BuilderBase;
|
|
||||||
use SPC\builder\LibraryBase;
|
|
||||||
use SPC\builder\linux\LinuxBuilder;
|
|
||||||
use SPC\builder\traits\UnixLibraryTrait;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
abstract class LinuxLibraryBase extends LibraryBase
|
|
||||||
{
|
|
||||||
use UnixLibraryTrait;
|
|
||||||
|
|
||||||
protected array $static_libs = [];
|
|
||||||
|
|
||||||
protected array $headers;
|
|
||||||
|
|
||||||
protected array $pkgconfs;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 依赖的名字及是否可选,例如:curl => true,代表依赖 curl 但可选
|
|
||||||
*/
|
|
||||||
protected array $dep_names;
|
|
||||||
|
|
||||||
public function __construct(protected LinuxBuilder $builder)
|
|
||||||
{
|
|
||||||
parent::__construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBuilder(): BuilderBase
|
|
||||||
{
|
|
||||||
return $this->builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function tryBuild(bool $force_build = false): int
|
|
||||||
{
|
|
||||||
// 传入 true,表明直接编译
|
|
||||||
if ($force_build) {
|
|
||||||
logger()->info('Building required library ' . static::NAME);
|
|
||||||
$this->build();
|
|
||||||
return BUILD_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 看看这些库是不是存在,如果不存在,则调用编译并返回结果状态
|
|
||||||
foreach ($this->getStaticLibs() as $name) {
|
|
||||||
if (!file_exists(BUILD_LIB_PATH . "/{$name}")) {
|
|
||||||
$this->tryBuild(true);
|
|
||||||
return BUILD_STATUS_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 头文件同理
|
|
||||||
foreach ($this->getHeaders() as $name) {
|
|
||||||
if (!file_exists(BUILD_INCLUDE_PATH . "/{$name}")) {
|
|
||||||
$this->tryBuild(true);
|
|
||||||
return BUILD_STATUS_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 到这里说明所有的文件都存在,就跳过编译
|
|
||||||
return BUILD_STATUS_ALREADY;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function makeFakePkgconfs()
|
|
||||||
{
|
|
||||||
$workspace = BUILD_ROOT_PATH;
|
|
||||||
if ($workspace === '/') {
|
|
||||||
$workspace = '';
|
|
||||||
}
|
|
||||||
foreach ($this->pkgconfs as $name => $content) {
|
|
||||||
file_put_contents(BUILD_LIB_PATH . "/pkgconfig/{$name}", "prefix={$workspace}\n" . $content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class brotli extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'brotli';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function build()
|
|
||||||
{
|
|
||||||
[$lib, $include, $destdir] = SEPARATED_PATH;
|
|
||||||
// 清理旧的编译文件
|
|
||||||
shell()->cd($this->source_dir)
|
|
||||||
->exec('rm -rf build')
|
|
||||||
->exec('mkdir -p build');
|
|
||||||
// 使用 cmake 编译
|
|
||||||
shell()->cd($this->source_dir . '/build')
|
|
||||||
->exec(
|
|
||||||
$this->builder->configure_env . ' cmake ' .
|
|
||||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
|
||||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
|
||||||
'-DCMAKE_INSTALL_PREFIX=/ ' .
|
|
||||||
"-DCMAKE_INSTALL_LIBDIR={$lib} " .
|
|
||||||
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
|
|
||||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
|
||||||
'..'
|
|
||||||
)
|
|
||||||
->exec("cmake --build . -j {$this->builder->concurrency} --target brotlicommon-static")
|
|
||||||
->exec("cmake --build . -j {$this->builder->concurrency} --target brotlidec-static")
|
|
||||||
->exec("cmake --build . -j {$this->builder->concurrency} --target brotlienc-static")
|
|
||||||
->exec('cp libbrotlidec-static.a ' . BUILD_LIB_PATH)
|
|
||||||
->exec('cp libbrotlienc-static.a ' . BUILD_LIB_PATH)
|
|
||||||
->exec('cp libbrotlicommon-static.a ' . BUILD_LIB_PATH)
|
|
||||||
->exec('cp -r ../c/include/brotli ' . BUILD_INCLUDE_PATH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class bzip2 extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'bzip2';
|
|
||||||
|
|
||||||
protected array $dep_names = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function build()
|
|
||||||
{
|
|
||||||
shell()
|
|
||||||
->cd($this->source_dir)
|
|
||||||
->exec("make {$this->builder->configure_env} PREFIX='" . BUILD_ROOT_PATH . "' clean")
|
|
||||||
->exec("make -j{$this->builder->concurrency} {$this->builder->configure_env} PREFIX='" . BUILD_ROOT_PATH . "' libbz2.a")
|
|
||||||
->exec('cp libbz2.a ' . BUILD_LIB_PATH)
|
|
||||||
->exec('cp bzlib.h ' . BUILD_INCLUDE_PATH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class curl extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'curl';
|
|
||||||
|
|
||||||
protected array $static_libs = ['libcurl.a'];
|
|
||||||
|
|
||||||
protected array $headers = ['curl'];
|
|
||||||
|
|
||||||
protected array $pkgconfs = [
|
|
||||||
'libcurl.pc' => <<<'EOF'
|
|
||||||
exec_prefix=${prefix}
|
|
||||||
libdir=${exec_prefix}/lib
|
|
||||||
includedir=${prefix}/include
|
|
||||||
supported_protocols="DICT FILE FTP FTPS GOPHER GOPHERS HTTP HTTPS IMAP IMAPS MQTT POP3 POP3S RTSP SCP SFTP SMB SMBS SMTP SMTPS TELNET TFTP"
|
|
||||||
supported_features="AsynchDNS GSS-API HSTS HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile NTLM NTLM_WB PSL SPNEGO SSL TLS-SRP UnixSockets alt-svc brotli libz zstd"
|
|
||||||
|
|
||||||
Name: libcurl
|
|
||||||
URL: https://curl.se/
|
|
||||||
Description: Library to transfer files with ftp, http, etc.
|
|
||||||
Version: 7.83.0
|
|
||||||
Libs: -L${libdir} -lcurl
|
|
||||||
Libs.private: -lnghttp2 -lidn2 -lssh2 -lssh2 -lpsl -lssl -lcrypto -lssl -lcrypto -lgssapi_krb5 -lzstd -lbrotlidec -lz
|
|
||||||
Cflags: -I${includedir}
|
|
||||||
EOF
|
|
||||||
];
|
|
||||||
|
|
||||||
protected array $dep_names = [
|
|
||||||
'zlib' => false,
|
|
||||||
'libssh2' => true,
|
|
||||||
'brotli' => true,
|
|
||||||
'nghttp2' => true,
|
|
||||||
'zstd' => true,
|
|
||||||
'openssl' => true,
|
|
||||||
'idn2' => true,
|
|
||||||
'psl' => true,
|
|
||||||
];
|
|
||||||
|
|
||||||
public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true): string
|
|
||||||
{
|
|
||||||
$libs = parent::getStaticLibFiles($style, $recursive);
|
|
||||||
if ($this->builder->getLib('openssl')) {
|
|
||||||
$libs .= ' -ldl -lpthread';
|
|
||||||
}
|
|
||||||
return $libs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function build()
|
|
||||||
{
|
|
||||||
$extra = '';
|
|
||||||
// lib:openssl
|
|
||||||
$openssl = $this->builder->getLib('openssl');
|
|
||||||
$use_openssl = $openssl instanceof LinuxLibraryBase ? 'ON' : 'OFF';
|
|
||||||
$extra .= "-DCURL_USE_OPENSSL={$use_openssl} -DCURL_ENABLE_SSL={$use_openssl} ";
|
|
||||||
// lib:zlib
|
|
||||||
$zlib = $this->builder->getLib('zlib');
|
|
||||||
if ($zlib instanceof LinuxLibraryBase) {
|
|
||||||
$extra .= '-DZLIB_LIBRARIES="' . $zlib->getStaticLibFiles(style: 'cmake') . '" ' .
|
|
||||||
'-DZLIB_INCLUDE_DIRS="' . BUILD_INCLUDE_PATH . '" ';
|
|
||||||
}
|
|
||||||
// lib:libssh2
|
|
||||||
$libssh2 = $this->builder->getLib('libssh2');
|
|
||||||
if ($libssh2 instanceof LinuxLibraryBase) {
|
|
||||||
$extra .= '-DLIBSSH2_LIBRARY="' . $libssh2->getStaticLibFiles(style: 'cmake') . '" ' .
|
|
||||||
'-DLIBSSH2_INCLUDE_DIR="' . BUILD_INCLUDE_PATH . '" ';
|
|
||||||
} else {
|
|
||||||
$extra .= '-DCURL_USE_LIBSSH2=OFF ';
|
|
||||||
}
|
|
||||||
// lib:brotli
|
|
||||||
$brotli = $this->builder->getLib('brotli');
|
|
||||||
if ($brotli) {
|
|
||||||
$extra .= '-DCURL_BROTLI=ON ' .
|
|
||||||
'-DBROTLIDEC_LIBRARY="' . realpath(BUILD_LIB_PATH . '/libbrotlidec-static.a') . ';' . realpath(BUILD_LIB_PATH . '/libbrotlicommon-static.a') . '" ' .
|
|
||||||
'-DBROTLICOMMON_LIBRARY="' . realpath(BUILD_LIB_PATH . '/libbrotlicommon-static.a') . '" ' .
|
|
||||||
'-DBROTLI_INCLUDE_DIR="' . BUILD_INCLUDE_PATH . '" ';
|
|
||||||
} else {
|
|
||||||
$extra .= '-DCURL_BROTLI=OFF ';
|
|
||||||
}
|
|
||||||
// lib:nghttp2
|
|
||||||
$nghttp2 = $this->builder->getLib('nghttp2');
|
|
||||||
if ($nghttp2 instanceof LinuxLibraryBase) {
|
|
||||||
$extra .= '-DUSE_NGHTTP2=ON ' .
|
|
||||||
'-DNGHTTP2_LIBRARY="' . $nghttp2->getStaticLibFiles(style: 'cmake') . '" ' .
|
|
||||||
'-DNGHTTP2_INCLUDE_DIR="' . BUILD_INCLUDE_PATH . '" ';
|
|
||||||
} else {
|
|
||||||
$extra .= '-DUSE_NGHTTP2=OFF ';
|
|
||||||
}
|
|
||||||
// lib:ldap
|
|
||||||
$ldap = $this->builder->getLib('ldap');
|
|
||||||
if ($ldap instanceof LinuxLibraryBase) {
|
|
||||||
// $extra .= '-DCURL_DISABLE_LDAP=OFF ';
|
|
||||||
// TODO: LDAP support
|
|
||||||
throw new RuntimeException('LDAP support is not implemented yet');
|
|
||||||
}
|
|
||||||
$extra .= '-DCURL_DISABLE_LDAP=ON ';
|
|
||||||
// lib:zstd
|
|
||||||
$zstd = $this->builder->getLib('zstd');
|
|
||||||
if ($zstd instanceof LinuxLibraryBase) {
|
|
||||||
$extra .= '-DCURL_ZSTD=ON ' .
|
|
||||||
'-DZstd_LIBRARY="' . $zstd->getStaticLibFiles(style: 'cmake') . '" ' .
|
|
||||||
'-DZstd_INCLUDE_DIR="' . BUILD_INCLUDE_PATH . '" ';
|
|
||||||
} else {
|
|
||||||
$extra .= '-DCURL_ZSTD=OFF ';
|
|
||||||
}
|
|
||||||
// lib:idn2
|
|
||||||
$idn2 = $this->builder->getLib('idn2');
|
|
||||||
$extra .= $idn2 instanceof LinuxLibraryBase ? '-DUSE_LIBIDN2=ON ' : '-DUSE_LIBIDN2=OFF ';
|
|
||||||
// lib:psl
|
|
||||||
$libpsl = $this->builder->getLib('psl');
|
|
||||||
$extra .= $libpsl instanceof LinuxLibraryBase ? '-DCURL_USE_LIBPSL=ON ' : '-DCURL_USE_LIBPSL=OFF ';
|
|
||||||
|
|
||||||
[$lib, $include, $destdir] = SEPARATED_PATH;
|
|
||||||
// compile!
|
|
||||||
shell()
|
|
||||||
->cd($this->source_dir)
|
|
||||||
->exec('rm -rf build')
|
|
||||||
->exec('mkdir -p build')
|
|
||||||
->cd($this->source_dir . '/build')
|
|
||||||
->exec("{$this->builder->configure_env} cmake " .
|
|
||||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
|
||||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
|
||||||
$extra .
|
|
||||||
'-DCMAKE_INSTALL_PREFIX=/ ' .
|
|
||||||
"-DCMAKE_INSTALL_LIBDIR={$lib} " .
|
|
||||||
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
|
|
||||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
|
||||||
'..')
|
|
||||||
->exec("make -j{$this->builder->concurrency}")
|
|
||||||
->exec("make install DESTDIR='{$destdir}'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gmp is a template library class for unix
|
|
||||||
*/
|
|
||||||
class gmp extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'gmp';
|
|
||||||
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
shell()->cd($this->source_dir)
|
|
||||||
->exec(
|
|
||||||
"{$this->builder->configure_env} ./configure " .
|
|
||||||
'--enable-static --disable-shared ' .
|
|
||||||
'--prefix='
|
|
||||||
)
|
|
||||||
->exec('make clean')
|
|
||||||
->exec("make -j{$this->builder->concurrency}")
|
|
||||||
->exec("make install DESTDIR={$destdir}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class libiconv extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'libiconv';
|
|
||||||
|
|
||||||
protected array $dep_names = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function build()
|
|
||||||
{
|
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
shell()->cd($this->source_dir)
|
|
||||||
->exec(
|
|
||||||
"{$this->builder->configure_env} ./configure " .
|
|
||||||
'--enable-static ' .
|
|
||||||
'--disable-shared ' .
|
|
||||||
'--prefix='
|
|
||||||
)
|
|
||||||
->exec('make clean')
|
|
||||||
->exec("make -j{$this->builder->concurrency}")
|
|
||||||
->exec('make install DESTDIR=' . $destdir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\util\Patcher;
|
|
||||||
|
|
||||||
class libpng extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'libpng';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public function build()
|
|
||||||
{
|
|
||||||
// 不同架构的专属优化
|
|
||||||
$optimizations = match ($this->builder->arch) {
|
|
||||||
'x86_64' => '--enable-intel-sse ',
|
|
||||||
'arm64' => '--enable-arm-neon ',
|
|
||||||
default => '',
|
|
||||||
};
|
|
||||||
|
|
||||||
// patch configure
|
|
||||||
Patcher::patchUnixLibpng();
|
|
||||||
|
|
||||||
shell()->cd($this->source_dir)
|
|
||||||
->exec(
|
|
||||||
"{$this->builder->configure_env} ./configure " .
|
|
||||||
"--host={$this->builder->gnu_arch}-unknown-linux " .
|
|
||||||
'--disable-shared ' .
|
|
||||||
'--enable-static ' .
|
|
||||||
'--enable-hardware-optimizations ' .
|
|
||||||
'--with-zlib-prefix=' . BUILD_ROOT_PATH . ' ' .
|
|
||||||
$optimizations .
|
|
||||||
'--prefix='
|
|
||||||
)
|
|
||||||
->exec('make clean')
|
|
||||||
->exec("make -j{$this->builder->concurrency} DEFAULT_INCLUDES='-I. -I" . BUILD_INCLUDE_PATH . "' LIBS= libpng16.la")
|
|
||||||
->exec('make install-libLTLIBRARIES install-data-am DESTDIR=' . BUILD_ROOT_PATH)
|
|
||||||
->cd(BUILD_LIB_PATH)
|
|
||||||
->exec('ln -sf libpng16.a libpng.a');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class libssh2 extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'libssh2';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function build()
|
|
||||||
{
|
|
||||||
// lib:zlib
|
|
||||||
$enable_zlib = $this->builder->getLib('zlib') !== null ? 'ON' : 'OFF';
|
|
||||||
|
|
||||||
[$lib, $include, $destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
shell()->cd($this->source_dir)
|
|
||||||
->exec('rm -rf build')
|
|
||||||
->exec('mkdir -p build')
|
|
||||||
->cd($this->source_dir . '/build')
|
|
||||||
->exec(
|
|
||||||
"{$this->builder->configure_env} " . ' cmake ' .
|
|
||||||
// '--debug-find ' .
|
|
||||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
|
||||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
|
||||||
'-DBUILD_EXAMPLES=OFF ' .
|
|
||||||
'-DBUILD_TESTING=OFF ' .
|
|
||||||
"-DENABLE_ZLIB_COMPRESSION={$enable_zlib} " .
|
|
||||||
'-DCMAKE_INSTALL_PREFIX=/ ' .
|
|
||||||
"-DCMAKE_INSTALL_LIBDIR={$lib} " .
|
|
||||||
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
|
|
||||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
|
||||||
'..'
|
|
||||||
)
|
|
||||||
->exec("cmake --build . -j {$this->builder->concurrency} --target libssh2")
|
|
||||||
->exec('make install DESTDIR="' . $destdir . '"');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* is a template library class for unix
|
|
||||||
*/
|
|
||||||
class libuv extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'libuv';
|
|
||||||
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
shell()->cd($this->source_dir)
|
|
||||||
->exec('./autogen.sh')
|
|
||||||
->exec(
|
|
||||||
"{$this->builder->configure_env} ./configure " .
|
|
||||||
'--enable-static --disable-shared ' .
|
|
||||||
'--prefix='
|
|
||||||
)
|
|
||||||
->exec('make clean')
|
|
||||||
->exec("make -j{$this->builder->concurrency}")
|
|
||||||
->exec("make install DESTDIR={$destdir}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\store\FileSystem;
|
|
||||||
|
|
||||||
class libxml2 extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'libxml2';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function build()
|
|
||||||
{
|
|
||||||
$enable_zlib = $this->builder->getLib('zlib') ? 'ON' : 'OFF';
|
|
||||||
$enable_icu = $this->builder->getLib('icu') ? 'ON' : 'OFF';
|
|
||||||
$enable_xz = $this->builder->getLib('xz') ? 'ON' : 'OFF';
|
|
||||||
|
|
||||||
[$lib, $include, $destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
shell()->cd($this->source_dir)
|
|
||||||
->exec('rm -rf build')
|
|
||||||
->exec('mkdir -p build')
|
|
||||||
->cd($this->source_dir . '/build')
|
|
||||||
->exec(
|
|
||||||
"{$this->builder->configure_env} " . ' cmake ' .
|
|
||||||
// '--debug-find ' .
|
|
||||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
|
||||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
|
||||||
'-DLIBXML2_WITH_ICONV=ON ' .
|
|
||||||
'-DIconv_IS_BUILT_IN=OFF ' .
|
|
||||||
"-DLIBXML2_WITH_ZLIB={$enable_zlib} " .
|
|
||||||
"-DLIBXML2_WITH_ICU={$enable_icu} " .
|
|
||||||
"-DLIBXML2_WITH_LZMA={$enable_xz} " .
|
|
||||||
'-DLIBXML2_WITH_PYTHON=OFF ' .
|
|
||||||
'-DLIBXML2_WITH_PROGRAMS=OFF ' .
|
|
||||||
'-DLIBXML2_WITH_TESTS=OFF ' .
|
|
||||||
'-DCMAKE_INSTALL_PREFIX=/ ' .
|
|
||||||
"-DCMAKE_INSTALL_LIBDIR={$lib} " .
|
|
||||||
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
|
|
||||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
|
||||||
'..'
|
|
||||||
)
|
|
||||||
->exec("cmake --build . -j {$this->builder->concurrency}")
|
|
||||||
->exec('make install DESTDIR="' . $destdir . '"');
|
|
||||||
|
|
||||||
if (is_dir(BUILD_INCLUDE_PATH . '/libxml2/libxml')) {
|
|
||||||
if (is_dir(BUILD_INCLUDE_PATH . '/libxml')) {
|
|
||||||
shell()->exec('rm -rf "' . BUILD_INCLUDE_PATH . '/libxml"');
|
|
||||||
}
|
|
||||||
$path = FileSystem::convertPath(BUILD_INCLUDE_PATH . '/libxml2/libxml');
|
|
||||||
$dst_path = FileSystem::convertPath(BUILD_INCLUDE_PATH . '/');
|
|
||||||
shell()->exec('mv "' . $path . '" "' . $dst_path . '"');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class libyaml extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'libyaml';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function build()
|
|
||||||
{
|
|
||||||
// prepare cmake/config.h.in
|
|
||||||
if (!is_file(SOURCE_PATH . '/libyaml/cmake/config.h.in')) {
|
|
||||||
f_mkdir(SOURCE_PATH . '/libyaml/cmake');
|
|
||||||
file_put_contents(
|
|
||||||
SOURCE_PATH . '/libyaml/cmake/config.h.in',
|
|
||||||
<<<'EOF'
|
|
||||||
#define YAML_VERSION_MAJOR @YAML_VERSION_MAJOR@
|
|
||||||
#define YAML_VERSION_MINOR @YAML_VERSION_MINOR@
|
|
||||||
#define YAML_VERSION_PATCH @YAML_VERSION_PATCH@
|
|
||||||
#define YAML_VERSION_STRING "@YAML_VERSION_STRING@"
|
|
||||||
EOF
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare yamlConfig.cmake.in
|
|
||||||
if (!is_file(SOURCE_PATH . '/libyaml/yamlConfig.cmake.in')) {
|
|
||||||
file_put_contents(
|
|
||||||
SOURCE_PATH . '/libyaml/yamlConfig.cmake.in',
|
|
||||||
<<<'EOF'
|
|
||||||
# Config file for the yaml library.
|
|
||||||
#
|
|
||||||
# It defines the following variables:
|
|
||||||
# yaml_LIBRARIES - libraries to link against
|
|
||||||
|
|
||||||
@PACKAGE_INIT@
|
|
||||||
|
|
||||||
set_and_check(yaml_TARGETS "@PACKAGE_CONFIG_DIR_CONFIG@/yamlTargets.cmake")
|
|
||||||
|
|
||||||
if(NOT yaml_TARGETS_IMPORTED)
|
|
||||||
set(yaml_TARGETS_IMPORTED 1)
|
|
||||||
include(${yaml_TARGETS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(yaml_LIBRARIES yaml)
|
|
||||||
|
|
||||||
EOF
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
[$lib, $include, $destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
shell()
|
|
||||||
->cd($this->source_dir)
|
|
||||||
->exec('rm -rf build')
|
|
||||||
->exec('mkdir -p build')
|
|
||||||
->cd($this->source_dir . '/build')
|
|
||||||
->exec("{$this->builder->configure_env} cmake " .
|
|
||||||
// '--debug-find ' .
|
|
||||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
|
||||||
'-DBUILD_TESTING=OFF ' .
|
|
||||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
|
||||||
'-DCMAKE_INSTALL_PREFIX=/ ' .
|
|
||||||
"-DCMAKE_INSTALL_LIBDIR={$lib} " .
|
|
||||||
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
|
|
||||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
|
||||||
'..')
|
|
||||||
->exec("make -j{$this->builder->concurrency}")
|
|
||||||
->exec("make install DESTDIR={$destdir}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class libzip extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'libzip';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws FileSystemException|RuntimeException
|
|
||||||
*/
|
|
||||||
public function build()
|
|
||||||
{
|
|
||||||
$extra = '';
|
|
||||||
// lib:zlib
|
|
||||||
$zlib = $this->builder->getLib('zlib');
|
|
||||||
if ($zlib instanceof LinuxLibraryBase) {
|
|
||||||
$extra .= '-DZLIB_LIBRARY="' . $zlib->getStaticLibFiles(style: 'cmake') . '" ' .
|
|
||||||
'-DZLIB_INCLUDE_DIR=' . BUILD_INCLUDE_PATH . ' ';
|
|
||||||
}
|
|
||||||
// lib:bzip2
|
|
||||||
$libbzip2 = $this->builder->getLib('bzip2');
|
|
||||||
if ($libbzip2 instanceof LinuxLibraryBase) {
|
|
||||||
$extra .= '-DENABLE_BZIP2=ON ' .
|
|
||||||
'-DBZIP2_LIBRARIES="' . $libbzip2->getStaticLibFiles(style: 'cmake') . '" ' .
|
|
||||||
'-DBZIP2_INCLUDE_DIR=' . BUILD_INCLUDE_PATH . ' ';
|
|
||||||
} else {
|
|
||||||
$extra .= '-DENABLE_BZIP2=OFF ';
|
|
||||||
}
|
|
||||||
// lib:xz
|
|
||||||
$xz = $this->builder->getLib('xz');
|
|
||||||
if ($xz instanceof LinuxLibraryBase) {
|
|
||||||
$extra .= '-DENABLE_LZMA=ON ' .
|
|
||||||
'-DLIBLZMA_LIBRARY="' . $xz->getStaticLibFiles(style: 'cmake') . '" ' .
|
|
||||||
'-DLIBLZMA_INCLUDE_DIR=' . BUILD_INCLUDE_PATH . ' ';
|
|
||||||
} else {
|
|
||||||
$extra .= '-DENABLE_LZMA=OFF ';
|
|
||||||
}
|
|
||||||
// lib:zstd
|
|
||||||
$libzstd = $this->builder->getLib('zstd');
|
|
||||||
if ($libzstd instanceof LinuxLibraryBase) {
|
|
||||||
$extra .= '-DENABLE_ZSTD=ON ' .
|
|
||||||
'-DZstd_LIBRARY="' . $libzstd->getStaticLibFiles(style: 'cmake') . '" ' .
|
|
||||||
'-DZstd_INCLUDE_DIR="' . BUILD_INCLUDE_PATH . '" ';
|
|
||||||
} else {
|
|
||||||
$extra .= '-DENABLE_ZSTD=OFF ';
|
|
||||||
}
|
|
||||||
// lib:openssl
|
|
||||||
$libopenssl = $this->builder->getLib('openssl');
|
|
||||||
if ($libopenssl instanceof LinuxLibraryBase) {
|
|
||||||
$extra .= '-DENABLE_OPENSSL=ON ' .
|
|
||||||
'-DOpenSSL_LIBRARY="' . $libopenssl->getStaticLibFiles(style: 'cmake') . '" ' .
|
|
||||||
'-DOpenSSL_INCLUDE_DIR="' . BUILD_INCLUDE_PATH . '" ';
|
|
||||||
} else {
|
|
||||||
$extra .= '-DENABLE_OPENSSL=OFF ';
|
|
||||||
}
|
|
||||||
|
|
||||||
[$lib, $include, $destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
shell()
|
|
||||||
->cd($this->source_dir)
|
|
||||||
->exec('rm -rf build')
|
|
||||||
->exec('mkdir -p build')
|
|
||||||
->cd($this->source_dir . '/build')
|
|
||||||
->exec(
|
|
||||||
$this->builder->configure_env . ' cmake ' .
|
|
||||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
|
||||||
'-DENABLE_GNUTLS=OFF ' .
|
|
||||||
'-DENABLE_MBEDTLS=OFF ' .
|
|
||||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
|
||||||
'-DBUILD_DOC=OFF ' .
|
|
||||||
'-DBUILD_EXAMPLES=OFF ' .
|
|
||||||
'-DBUILD_REGRESS=OFF ' .
|
|
||||||
'-DBUILD_TOOLS=OFF ' .
|
|
||||||
$extra .
|
|
||||||
'-DCMAKE_INSTALL_PREFIX=/ ' .
|
|
||||||
"-DCMAKE_INSTALL_LIBDIR={$lib} " .
|
|
||||||
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
|
|
||||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
|
||||||
'..'
|
|
||||||
)
|
|
||||||
->exec("make -j{$this->builder->concurrency}")
|
|
||||||
->exec('make install DESTDIR=' . $destdir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class nghttp2 extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'nghttp2';
|
|
||||||
|
|
||||||
protected array $static_libs = ['libnghttp2.a'];
|
|
||||||
|
|
||||||
protected array $headers = ['nghttp2'];
|
|
||||||
|
|
||||||
protected array $pkgconfs = [
|
|
||||||
'libnghttp2.pc' => <<<'EOF'
|
|
||||||
exec_prefix=${prefix}
|
|
||||||
libdir=${exec_prefix}/lib
|
|
||||||
includedir=${prefix}/include
|
|
||||||
|
|
||||||
Name: libnghttp2
|
|
||||||
Description: HTTP/2 C library
|
|
||||||
URL: https://github.com/tatsuhiro-t/nghttp2
|
|
||||||
Version: 1.47.0
|
|
||||||
Libs: -L${libdir} -lnghttp2
|
|
||||||
Cflags: -I${includedir}
|
|
||||||
EOF
|
|
||||||
];
|
|
||||||
|
|
||||||
protected array $dep_names = [
|
|
||||||
'zlib' => false,
|
|
||||||
'openssl' => false,
|
|
||||||
'libxml2' => true,
|
|
||||||
'libev' => true,
|
|
||||||
'libcares' => true,
|
|
||||||
'libngtcp2' => true,
|
|
||||||
'libnghttp3' => true,
|
|
||||||
'libbpf' => true,
|
|
||||||
'libevent-openssl' => true,
|
|
||||||
'jansson' => true,
|
|
||||||
'jemalloc' => true,
|
|
||||||
'systemd' => true,
|
|
||||||
'cunit' => true,
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function build()
|
|
||||||
{
|
|
||||||
$args = $this->builder->makeAutoconfArgs(static::NAME, [
|
|
||||||
'zlib' => null,
|
|
||||||
'openssl' => null,
|
|
||||||
'libxml2' => null,
|
|
||||||
'libev' => null,
|
|
||||||
'libcares' => null,
|
|
||||||
'libngtcp2' => null,
|
|
||||||
'libnghttp3' => null,
|
|
||||||
'libbpf' => null,
|
|
||||||
'libevent-openssl' => null,
|
|
||||||
'jansson' => null,
|
|
||||||
'jemalloc' => null,
|
|
||||||
'systemd' => null,
|
|
||||||
'cunit' => null,
|
|
||||||
]);
|
|
||||||
|
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
shell()->cd($this->source_dir)
|
|
||||||
->exec(
|
|
||||||
"{$this->builder->configure_env} ./configure " .
|
|
||||||
'--enable-static ' .
|
|
||||||
'--disable-shared ' .
|
|
||||||
"--host={$this->builder->gnu_arch}-unknown-linux " .
|
|
||||||
'--enable-lib-only ' .
|
|
||||||
'--with-boost=no ' .
|
|
||||||
$args . ' ' .
|
|
||||||
'--prefix='
|
|
||||||
)
|
|
||||||
->exec('make clean')
|
|
||||||
->exec("make -j{$this->builder->concurrency}")
|
|
||||||
->exec("make install DESTDIR={$destdir}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class onig extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'onig';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function build()
|
|
||||||
{
|
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
shell()->cd($this->source_dir)
|
|
||||||
->exec(
|
|
||||||
"{$this->builder->configure_env} ./configure " .
|
|
||||||
'--enable-static ' .
|
|
||||||
'--disable-shared ' .
|
|
||||||
"--host={$this->builder->arch}-unknown-linux " .
|
|
||||||
'--prefix='
|
|
||||||
)
|
|
||||||
->exec('make clean')
|
|
||||||
->exec("make -j{$this->builder->concurrency}")
|
|
||||||
->exec("make install DESTDIR={$destdir}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
use SPC\builder\linux\SystemUtil;
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class openssl extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'openssl';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public function build()
|
|
||||||
{
|
|
||||||
[$lib,$include,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
$extra = '';
|
|
||||||
$ex_lib = '-ldl -pthread';
|
|
||||||
|
|
||||||
$env = $this->builder->pkgconf_env . " CFLAGS='{$this->builder->arch_c_flags}'";
|
|
||||||
$env .= " CC='{$this->builder->cc} --static -static-libgcc -idirafter " . BUILD_INCLUDE_PATH .
|
|
||||||
' -idirafter /usr/include/ ' .
|
|
||||||
' -idirafter /usr/include/' . $this->builder->arch . '-linux-gnu/ ' .
|
|
||||||
"' ";
|
|
||||||
// lib:zlib
|
|
||||||
$zlib = $this->builder->getLib('zlib');
|
|
||||||
if ($zlib instanceof LinuxLibraryBase) {
|
|
||||||
$extra = 'zlib';
|
|
||||||
$ex_lib = trim($zlib->getStaticLibFiles() . ' ' . $ex_lib);
|
|
||||||
$zlib_extra =
|
|
||||||
'--with-zlib-include=' . BUILD_INCLUDE_PATH . ' ' .
|
|
||||||
'--with-zlib-lib=' . BUILD_LIB_PATH . ' ';
|
|
||||||
} else {
|
|
||||||
$zlib_extra = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$ex_lib = trim($ex_lib);
|
|
||||||
|
|
||||||
$clang_postfix = SystemUtil::getCCType($this->builder->cc) === 'clang' ? '-clang' : '';
|
|
||||||
|
|
||||||
shell()->cd($this->source_dir)
|
|
||||||
->exec(
|
|
||||||
"{$this->builder->configure_env} {$env} ./Configure no-shared {$extra} " .
|
|
||||||
'--prefix=/ ' .
|
|
||||||
"--libdir={$lib} " .
|
|
||||||
'--static -static ' .
|
|
||||||
"{$zlib_extra}" .
|
|
||||||
'no-legacy ' .
|
|
||||||
"linux-{$this->builder->arch}{$clang_postfix}"
|
|
||||||
)
|
|
||||||
->exec('make clean')
|
|
||||||
->exec("make -j{$this->builder->concurrency} CNF_EX_LIBS=\"{$ex_lib}\"")
|
|
||||||
->exec("make install_sw DESTDIR={$destdir}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class sqlite extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'sqlite';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function build()
|
|
||||||
{
|
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
shell()->cd($this->source_dir)
|
|
||||||
->exec(
|
|
||||||
"{$this->builder->configure_env} ./configure " .
|
|
||||||
'--enable-static ' .
|
|
||||||
'--disable-shared ' .
|
|
||||||
'--prefix='
|
|
||||||
)
|
|
||||||
->exec('make clean')
|
|
||||||
->exec("make -j{$this->builder->concurrency}")
|
|
||||||
->exec("make install DESTDIR={$destdir}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class xz extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'xz';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function build()
|
|
||||||
{
|
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
shell()->cd($this->source_dir)
|
|
||||||
// ->exec('autoreconf -i --force')
|
|
||||||
->exec(
|
|
||||||
"{$this->builder->configure_env} ./configure " .
|
|
||||||
'--enable-static ' .
|
|
||||||
'--disable-shared ' .
|
|
||||||
"--host={$this->builder->gnu_arch}-unknown-linux " .
|
|
||||||
'--disable-xz ' .
|
|
||||||
'--disable-xzdec ' .
|
|
||||||
'--disable-lzmadec ' .
|
|
||||||
'--disable-lzmainfo ' .
|
|
||||||
'--disable-scripts ' .
|
|
||||||
'--disable-doc ' .
|
|
||||||
'--with-libiconv ' .
|
|
||||||
'--prefix='
|
|
||||||
)
|
|
||||||
->exec('make clean')
|
|
||||||
->exec("make -j{$this->builder->concurrency}")
|
|
||||||
->exec("make install DESTDIR={$destdir}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class zlib extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'zlib';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function build()
|
|
||||||
{
|
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
shell()->cd($this->source_dir)
|
|
||||||
->exec(
|
|
||||||
"{$this->builder->configure_env} ./configure " .
|
|
||||||
'--static ' .
|
|
||||||
'--prefix='
|
|
||||||
)
|
|
||||||
->exec('make clean')
|
|
||||||
->exec("make -j{$this->builder->concurrency}")
|
|
||||||
->exec("make install DESTDIR={$destdir}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class zstd extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'zstd';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function build()
|
|
||||||
{
|
|
||||||
shell()->cd($this->source_dir)
|
|
||||||
->exec("make {$this->builder->configure_env} PREFIX='" . BUILD_ROOT_PATH . "' clean")
|
|
||||||
->exec(
|
|
||||||
"make -j{$this->builder->concurrency} " .
|
|
||||||
"{$this->builder->configure_env} " .
|
|
||||||
"PREFIX='" . BUILD_ROOT_PATH . "' " .
|
|
||||||
'-C lib libzstd.a CPPFLAGS_STATLIB=-DZSTD_MULTITHREAD'
|
|
||||||
)
|
|
||||||
->exec('cp lib/libzstd.a ' . BUILD_LIB_PATH)
|
|
||||||
->exec('cp lib/zdict.h lib/zstd_errors.h lib/zstd.h ' . BUILD_INCLUDE_PATH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,266 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos;
|
|
||||||
|
|
||||||
use SPC\builder\BuilderBase;
|
|
||||||
use SPC\builder\macos\library\MacOSLibraryBase;
|
|
||||||
use SPC\builder\traits\UnixBuilderTrait;
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\util\Patcher;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* macOS 系统环境下的构建器
|
|
||||||
* 源于 Config,但因为感觉叫 Config 不太合适,就换成了 Builder
|
|
||||||
*/
|
|
||||||
class MacOSBuilder extends BuilderBase
|
|
||||||
{
|
|
||||||
/** 编译的 Unix 工具集 */
|
|
||||||
use UnixBuilderTrait;
|
|
||||||
|
|
||||||
/** @var string[] MacOS 环境下编译依赖的命令 */
|
|
||||||
public const REQUIRED_COMMANDS = ['make', 'bison', 'flex', 'pkg-config', 'git', 'autoconf', 'automake', 'tar', 'unzip', 'xz', 'gzip', 'bzip2', 'cmake'];
|
|
||||||
|
|
||||||
/** @var bool 标记是否 patch 了 phar */
|
|
||||||
private bool $phar_patched = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function __construct(?string $cc = null, ?string $cxx = null, ?string $arch = null)
|
|
||||||
{
|
|
||||||
// 如果是 Debug 模式,才使用 set -x 显示每条执行的命令
|
|
||||||
$this->set_x = defined('DEBUG_MODE') ? 'set -x' : 'true';
|
|
||||||
// 初始化一些默认参数
|
|
||||||
$this->cc = $cc ?? 'clang';
|
|
||||||
$this->cxx = $cxx ?? 'clang++';
|
|
||||||
$this->arch = $arch ?? php_uname('m');
|
|
||||||
$this->gnu_arch = arch2gnu($this->arch);
|
|
||||||
// 根据 CPU 线程数设置编译进程数
|
|
||||||
$this->concurrency = SystemUtil::getCpuCount();
|
|
||||||
// 设置 cflags
|
|
||||||
$this->arch_c_flags = SystemUtil::getArchCFlags($this->arch);
|
|
||||||
$this->arch_cxx_flags = SystemUtil::getArchCFlags($this->arch);
|
|
||||||
// 设置 cmake
|
|
||||||
$this->cmake_toolchain_file = SystemUtil::makeCmakeToolchainFile('Darwin', $this->arch, $this->arch_c_flags);
|
|
||||||
// 设置 configure 依赖的环境变量
|
|
||||||
$this->configure_env =
|
|
||||||
'PKG_CONFIG_PATH="' . BUILD_LIB_PATH . '/pkgconfig/" ' .
|
|
||||||
"CC='{$this->cc}' " .
|
|
||||||
"CXX='{$this->cxx}' " .
|
|
||||||
"CFLAGS='{$this->arch_c_flags} -Wimplicit-function-declaration'";
|
|
||||||
// 保存丢失的命令
|
|
||||||
$missing = [];
|
|
||||||
foreach (self::REQUIRED_COMMANDS as $cmd) {
|
|
||||||
if (SystemUtil::findCommand($cmd) === null) {
|
|
||||||
$missing[] = $cmd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!empty($missing)) {
|
|
||||||
throw new RuntimeException('missing system commands: ' . implode(', ', $missing));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创立 pkg-config 和放头文件的目录
|
|
||||||
f_mkdir(BUILD_LIB_PATH . '/pkgconfig', recursive: true);
|
|
||||||
f_mkdir(BUILD_INCLUDE_PATH, recursive: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成库构建采用的 autoconf 参数列表
|
|
||||||
*
|
|
||||||
* @param string $name 要构建的 lib 库名,传入仅供输出日志
|
|
||||||
* @param array $lib_specs 依赖的 lib 库的 autoconf 文件
|
|
||||||
*/
|
|
||||||
public function makeAutoconfArgs(string $name, array $lib_specs): string
|
|
||||||
{
|
|
||||||
$ret = '';
|
|
||||||
foreach ($lib_specs as $libName => $arr) {
|
|
||||||
$lib = $this->getLib($libName);
|
|
||||||
|
|
||||||
$arr = $arr ?? [];
|
|
||||||
|
|
||||||
$disableArgs = $arr[0] ?? null;
|
|
||||||
$prefix = $arr[1] ?? null;
|
|
||||||
if ($lib instanceof MacOSLibraryBase) {
|
|
||||||
logger()->info("{$name} \033[32;1mwith\033[0;1m {$libName} support");
|
|
||||||
$ret .= $lib->makeAutoconfEnv($prefix) . ' ';
|
|
||||||
} else {
|
|
||||||
logger()->info("{$name} \033[31;1mwithout\033[0;1m {$libName} support");
|
|
||||||
$ret .= ($disableArgs ?? "--with-{$libName}=no") . ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rtrim($ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回 macOS 系统依赖的框架列表
|
|
||||||
*
|
|
||||||
* @param bool $asString 是否以字符串形式返回(默认为 False)
|
|
||||||
*/
|
|
||||||
public function getFrameworks(bool $asString = false): array|string
|
|
||||||
{
|
|
||||||
$libs = [];
|
|
||||||
|
|
||||||
// reorder libs
|
|
||||||
foreach ($this->libs as $lib) {
|
|
||||||
foreach ($lib->getDependencies() as $dep) {
|
|
||||||
$libs[] = $dep;
|
|
||||||
}
|
|
||||||
$libs[] = $lib;
|
|
||||||
}
|
|
||||||
|
|
||||||
$frameworks = [];
|
|
||||||
/** @var MacOSLibraryBase $lib */
|
|
||||||
foreach ($libs as $lib) {
|
|
||||||
array_push($frameworks, ...$lib->getFrameworks());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($asString) {
|
|
||||||
return implode(' ', array_map(fn ($x) => "-framework {$x}", $frameworks));
|
|
||||||
}
|
|
||||||
return $frameworks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public function buildPHP(int $build_micro_rule = BUILD_MICRO_NONE, bool $bloat = false): void
|
|
||||||
{
|
|
||||||
$extra_libs = $this->getFrameworks(true) . ' ' . ($this->getExt('swoole') ? '-lc++ ' : '');
|
|
||||||
if (!$bloat) {
|
|
||||||
$extra_libs .= implode(' ', $this->getAllStaticLibFiles());
|
|
||||||
} else {
|
|
||||||
logger()->info('bloat linking');
|
|
||||||
$extra_libs .= implode(
|
|
||||||
' ',
|
|
||||||
array_map(
|
|
||||||
fn ($x) => "-Wl,-force_load,{$x}",
|
|
||||||
array_filter($this->getAllStaticLibFiles())
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// patch before configure
|
|
||||||
Patcher::patchPHPBeforeConfigure($this);
|
|
||||||
|
|
||||||
f_passthru(
|
|
||||||
$this->set_x . ' && ' .
|
|
||||||
'cd ' . SOURCE_PATH . '/php-src && ' .
|
|
||||||
'./buildconf --force'
|
|
||||||
);
|
|
||||||
|
|
||||||
Patcher::patchPHPConfigure($this);
|
|
||||||
|
|
||||||
if ($this->getLib('libxml2') || $this->getExt('iconv')) {
|
|
||||||
$extra_libs .= ' -liconv';
|
|
||||||
}
|
|
||||||
|
|
||||||
f_passthru(
|
|
||||||
$this->set_x . ' && ' .
|
|
||||||
'cd ' . SOURCE_PATH . '/php-src && ' .
|
|
||||||
'./configure ' .
|
|
||||||
'--prefix= ' .
|
|
||||||
'--with-valgrind=no ' . // 不检测内存泄漏
|
|
||||||
'--enable-shared=no ' .
|
|
||||||
'--enable-static=yes ' .
|
|
||||||
"--host={$this->gnu_arch}-apple-darwin " .
|
|
||||||
"CFLAGS='{$this->arch_c_flags} -Werror=unknown-warning-option' " .
|
|
||||||
'--disable-all ' .
|
|
||||||
'--disable-cgi ' .
|
|
||||||
'--disable-phpdbg ' .
|
|
||||||
'--enable-cli ' .
|
|
||||||
'--enable-micro ' .
|
|
||||||
($this->zts ? '--enable-zts' : '') . ' ' .
|
|
||||||
$this->makeExtensionArgs() . ' ' .
|
|
||||||
$this->configure_env
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->cleanMake();
|
|
||||||
|
|
||||||
switch ($build_micro_rule) {
|
|
||||||
case BUILD_MICRO_NONE:
|
|
||||||
logger()->info('building cli');
|
|
||||||
$this->buildCli($extra_libs);
|
|
||||||
break;
|
|
||||||
case BUILD_MICRO_ONLY:
|
|
||||||
logger()->info('building micro');
|
|
||||||
$this->buildMicro($extra_libs);
|
|
||||||
break;
|
|
||||||
case BUILD_MICRO_BOTH:
|
|
||||||
logger()->info('building cli and micro');
|
|
||||||
$this->buildCli($extra_libs);
|
|
||||||
$this->buildMicro($extra_libs);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (php_uname('m') === $this->arch) {
|
|
||||||
$this->sanityCheck($build_micro_rule);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->phar_patched) {
|
|
||||||
f_passthru('cd ' . SOURCE_PATH . '/php-src && patch -p1 -R < sapi/micro/patches/phar.patch');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建 phpmicro
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function buildMicro(string $extra_libs): void
|
|
||||||
{
|
|
||||||
if ($this->getPHPVersionID() < 80000) {
|
|
||||||
throw new RuntimeException('phpmicro only support PHP >= 8.0!');
|
|
||||||
}
|
|
||||||
if ($this->getExt('phar')) {
|
|
||||||
$this->phar_patched = true;
|
|
||||||
try {
|
|
||||||
f_passthru('cd ' . SOURCE_PATH . '/php-src && patch -p1 < sapi/micro/patches/phar.patch');
|
|
||||||
} catch (RuntimeException $e) {
|
|
||||||
logger()->error('failed to patch phat due to patch exit with code ' . $e->getCode());
|
|
||||||
$this->phar_patched = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f_passthru(
|
|
||||||
$this->set_x . ' && ' .
|
|
||||||
'cd ' . SOURCE_PATH . '/php-src && ' .
|
|
||||||
"make -j{$this->concurrency} " .
|
|
||||||
'EXTRA_CFLAGS="-g -Os -fno-ident" ' .
|
|
||||||
"EXTRA_LIBS=\"{$extra_libs} -lresolv\" " .
|
|
||||||
'STRIP="dsymutil -f " ' .
|
|
||||||
// TODO: comment things
|
|
||||||
'micro'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建 cli
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function buildCli(string $extra_libs): void
|
|
||||||
{
|
|
||||||
f_passthru(
|
|
||||||
$this->set_x . ' && ' .
|
|
||||||
'cd ' . SOURCE_PATH . '/php-src && ' .
|
|
||||||
"make -j{$this->concurrency} " .
|
|
||||||
'EXTRA_CFLAGS="-g -Os -fno-ident" ' . // 生成调试信息、优化编译后的尺寸、禁用标识符(如变量、函数名)缩短
|
|
||||||
"EXTRA_LIBS=\"{$extra_libs} -lresolv\" " .
|
|
||||||
// TODO: comment things
|
|
||||||
'cli &&' .
|
|
||||||
'dsymutil -f sapi/cli/php &&' .
|
|
||||||
'strip sapi/cli/php'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPHPVersionID(): int
|
|
||||||
{
|
|
||||||
$file = file_get_contents(SOURCE_PATH . '/php-src/main/php_version.h');
|
|
||||||
preg_match('/PHP_VERSION_ID (\d+)/', $file, $match);
|
|
||||||
return intval($match[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos;
|
|
||||||
|
|
||||||
use SPC\builder\traits\UnixSystemUtilTrait;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class SystemUtil
|
|
||||||
{
|
|
||||||
/** macOS 兼容 unix 的系统工具 */
|
|
||||||
use UnixSystemUtilTrait;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取系统 CPU 逻辑内核数
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function getCpuCount(): int
|
|
||||||
{
|
|
||||||
[$ret, $output] = shell()->execWithResult('sysctl -n hw.ncpu');
|
|
||||||
if ($ret !== 0) {
|
|
||||||
throw new RuntimeException('Failed to get cpu count');
|
|
||||||
}
|
|
||||||
|
|
||||||
return (int) $output[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取不同架构对应的 cflags 参数
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function getArchCFlags(string $arch): string
|
|
||||||
{
|
|
||||||
return match ($arch) {
|
|
||||||
'x86_64' => '--target=x86_64-apple-darwin',
|
|
||||||
'arm64','aarch64' => '--target=arm64-apple-darwin',
|
|
||||||
default => throw new RuntimeException('unsupported arch: ' . $arch),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
use SPC\builder\BuilderBase;
|
|
||||||
use SPC\builder\LibraryBase;
|
|
||||||
use SPC\builder\macos\MacOSBuilder;
|
|
||||||
use SPC\builder\traits\UnixLibraryTrait;
|
|
||||||
use SPC\store\Config;
|
|
||||||
|
|
||||||
abstract class MacOSLibraryBase extends LibraryBase
|
|
||||||
{
|
|
||||||
use UnixLibraryTrait;
|
|
||||||
|
|
||||||
protected array $static_libs;
|
|
||||||
|
|
||||||
protected array $headers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 依赖的名字及是否可选,例如:curl => true,代表依赖 curl 但可选
|
|
||||||
*/
|
|
||||||
protected array $dep_names;
|
|
||||||
|
|
||||||
public function __construct(protected MacOSBuilder $builder)
|
|
||||||
{
|
|
||||||
parent::__construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBuilder(): BuilderBase
|
|
||||||
{
|
|
||||||
return $this->builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前 lib 库依赖的 macOS framework
|
|
||||||
*/
|
|
||||||
public function getFrameworks(): array
|
|
||||||
{
|
|
||||||
return Config::getLib(static::NAME, 'frameworks', []);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
class brotli extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'brotli';
|
|
||||||
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
[$lib, $include, $destdir] = SEPARATED_PATH;
|
|
||||||
f_passthru(
|
|
||||||
"{$this->builder->set_x} && " .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
'rm -rf build && ' .
|
|
||||||
'mkdir -p build && ' .
|
|
||||||
'cd build && ' .
|
|
||||||
"{$this->builder->configure_env} " . ' cmake ' .
|
|
||||||
// '--debug-find ' .
|
|
||||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
|
||||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
|
||||||
'-DCMAKE_INSTALL_PREFIX=/ ' .
|
|
||||||
"-DCMAKE_INSTALL_LIBDIR={$lib} " .
|
|
||||||
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
|
|
||||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
|
||||||
'.. && ' .
|
|
||||||
"cmake --build . -j {$this->builder->concurrency} && " .
|
|
||||||
'make install DESTDIR="' . $destdir . '"'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
class bzip2 extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'bzip2';
|
|
||||||
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
f_passthru(
|
|
||||||
$this->builder->set_x . ' && ' .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
"make {$this->builder->configure_env} PREFIX='" . BUILD_ROOT_PATH . "' clean" . ' && ' .
|
|
||||||
"make -j{$this->builder->concurrency} {$this->builder->configure_env} PREFIX='" . BUILD_ROOT_PATH . "' libbz2.a" . ' && ' .
|
|
||||||
// make install may fail when cross-compiling, so we copy files.
|
|
||||||
'cp libbz2.a ' . BUILD_LIB_PATH . ' && ' .
|
|
||||||
'cp bzlib.h ' . BUILD_INCLUDE_PATH
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class curl extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'curl';
|
|
||||||
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
$extra = '';
|
|
||||||
// lib:openssl
|
|
||||||
$openssl = $this->getBuilder()->getLib('openssl');
|
|
||||||
if ($openssl instanceof MacOSLibraryBase) {
|
|
||||||
$extra .= '-DCURL_USE_OPENSSL=ON ';
|
|
||||||
} else {
|
|
||||||
$extra .= '-DCURL_USE_OPENSSL=OFF -DCURL_ENABLE_SSL=OFF ';
|
|
||||||
}
|
|
||||||
// lib:zlib
|
|
||||||
$zlib = $this->getBuilder()->getLib('zlib');
|
|
||||||
if ($zlib instanceof MacOSLibraryBase) {
|
|
||||||
$extra .= '-DZLIB_LIBRARY="' . $zlib->getStaticLibFiles(style: 'cmake') . '" ' .
|
|
||||||
'-DZLIB_INCLUDE_DIR=' . BUILD_INCLUDE_PATH . ' ';
|
|
||||||
}
|
|
||||||
// lib:libssh2
|
|
||||||
$libssh2 = $this->builder->getLib('libssh2');
|
|
||||||
if ($libssh2 instanceof MacOSLibraryBase) {
|
|
||||||
$extra .= '-DLIBSSH2_LIBRARY="' . $libssh2->getStaticLibFiles(style: 'cmake') . '" ' .
|
|
||||||
'-DLIBSSH2_INCLUDE_DIR="' . BUILD_INCLUDE_PATH . '" ';
|
|
||||||
} else {
|
|
||||||
$extra .= '-DCURL_USE_LIBSSH2=OFF ';
|
|
||||||
}
|
|
||||||
// lib:brotli
|
|
||||||
$brotli = $this->builder->getLib('brotli');
|
|
||||||
if ($brotli) {
|
|
||||||
$extra .= '-DCURL_BROTLI=ON ' .
|
|
||||||
'-DBROTLIDEC_LIBRARY="' . realpath(BUILD_LIB_PATH . '/libbrotlidec-static.a') . ';' . realpath(BUILD_LIB_PATH . '/libbrotlicommon-static.a') . '" ' .
|
|
||||||
'-DBROTLICOMMON_LIBRARY="' . realpath(BUILD_LIB_PATH . '/libbrotlicommon-static.a') . '" ' .
|
|
||||||
'-DBROTLI_INCLUDE_DIR="' . BUILD_INCLUDE_PATH . '" ';
|
|
||||||
} else {
|
|
||||||
$extra .= '-DCURL_BROTLI=OFF ';
|
|
||||||
}
|
|
||||||
// lib:nghttp2
|
|
||||||
$nghttp2 = $this->builder->getLib('nghttp2');
|
|
||||||
if ($nghttp2 instanceof MacOSLibraryBase) {
|
|
||||||
$extra .= '-DUSE_NGHTTP2=ON ' .
|
|
||||||
'-DNGHTTP2_LIBRARY="' . $nghttp2->getStaticLibFiles(style: 'cmake') . '" ' .
|
|
||||||
'-DNGHTTP2_INCLUDE_DIR="' . BUILD_INCLUDE_PATH . '" ';
|
|
||||||
} else {
|
|
||||||
$extra .= '-DUSE_NGHTTP2=OFF ';
|
|
||||||
}
|
|
||||||
// lib:ldap
|
|
||||||
$ldap = $this->builder->getLib('ldap');
|
|
||||||
if ($ldap instanceof MacOSLibraryBase) {
|
|
||||||
// $extra .= '-DCURL_DISABLE_LDAP=OFF ';
|
|
||||||
// TODO: LDAP support
|
|
||||||
throw new RuntimeException('LDAP support is not implemented yet');
|
|
||||||
}
|
|
||||||
$extra .= '-DCURL_DISABLE_LDAP=ON ';
|
|
||||||
// lib:zstd
|
|
||||||
$zstd = $this->builder->getLib('zstd');
|
|
||||||
if ($zstd instanceof MacOSLibraryBase) {
|
|
||||||
$extra .= '-DCURL_ZSTD=ON ' .
|
|
||||||
'-DZstd_LIBRARY="' . $zstd->getStaticLibFiles(style: 'cmake') . '" ' .
|
|
||||||
'-DZstd_INCLUDE_DIR="' . BUILD_INCLUDE_PATH . '" ';
|
|
||||||
} else {
|
|
||||||
$extra .= '-DCURL_ZSTD=OFF ';
|
|
||||||
}
|
|
||||||
// lib:idn2
|
|
||||||
$idn2 = $this->builder->getLib('idn2');
|
|
||||||
$extra .= $idn2 instanceof MacOSLibraryBase ? '-DUSE_LIBIDN2=ON ' : '-DUSE_LIBIDN2=OFF ';
|
|
||||||
// lib:psl
|
|
||||||
$libpsl = $this->builder->getLib('psl');
|
|
||||||
$extra .= $libpsl instanceof MacOSLibraryBase ? '-DCURL_USE_LIBPSL=ON ' : '-DCURL_USE_LIBPSL=OFF ';
|
|
||||||
|
|
||||||
[$lib, $include, $destdir] = SEPARATED_PATH;
|
|
||||||
// compile!
|
|
||||||
f_passthru(
|
|
||||||
$this->builder->set_x . ' && ' .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
'rm -rf build && ' .
|
|
||||||
'mkdir -p build && ' .
|
|
||||||
'cd build && ' .
|
|
||||||
"{$this->builder->configure_env} " . ' cmake ' .
|
|
||||||
// '--debug-find ' .
|
|
||||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
|
||||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
|
||||||
$extra .
|
|
||||||
'-DCMAKE_INSTALL_PREFIX= ' .
|
|
||||||
"-DCMAKE_INSTALL_LIBDIR={$lib} " .
|
|
||||||
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
|
|
||||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
|
||||||
'.. && ' .
|
|
||||||
"make -j{$this->builder->concurrency} && " .
|
|
||||||
'make install DESTDIR="' . $destdir . '"'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* is a template library class for unix
|
|
||||||
*/
|
|
||||||
class freetype extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'freetype';
|
|
||||||
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
$suggested = '';
|
|
||||||
$suggested .= ($this->builder->getLib('libpng') instanceof MacOSLibraryBase) ? ('--with-png=' . BUILD_ROOT_PATH) : '--without-png';
|
|
||||||
$suggested .= ' ';
|
|
||||||
$suggested .= ($this->builder->getLib('bzip2') instanceof MacOSLibraryBase) ? ('--with-bzip2=' . BUILD_ROOT_PATH) : '--without-bzip2';
|
|
||||||
$suggested .= ' ';
|
|
||||||
$suggested .= ($this->builder->getLib('brotli') instanceof MacOSLibraryBase) ? ('--with-brotli=' . BUILD_ROOT_PATH) : '--without-brotli';
|
|
||||||
$suggested .= ' ';
|
|
||||||
|
|
||||||
f_passthru(
|
|
||||||
$this->builder->set_x . ' && ' .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
"{$this->builder->configure_env} ./configure " .
|
|
||||||
'--enable-static --disable-shared --without-harfbuzz ' .
|
|
||||||
$suggested .
|
|
||||||
'--prefix= && ' . // use prefix=/
|
|
||||||
'make clean && ' .
|
|
||||||
"make -j{$this->builder->concurrency} && " .
|
|
||||||
'make install DESTDIR=' . $destdir
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gmp is a template library class for unix
|
|
||||||
*/
|
|
||||||
class gmp extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'gmp';
|
|
||||||
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
f_passthru(
|
|
||||||
$this->builder->set_x . ' && ' .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
"{$this->builder->configure_env} ./configure " .
|
|
||||||
'--enable-static --disable-shared ' .
|
|
||||||
'--prefix= && ' . // use prefix=/
|
|
||||||
'make clean && ' .
|
|
||||||
"make -j{$this->builder->concurrency} && " .
|
|
||||||
'make install DESTDIR=' . $destdir
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
class libffi extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'libffi';
|
|
||||||
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
[$lib, $include, $destdir] = SEPARATED_PATH;
|
|
||||||
f_passthru(
|
|
||||||
$this->builder->set_x . ' && ' .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
"{$this->builder->configure_env} ./configure " .
|
|
||||||
'--enable-static ' .
|
|
||||||
'--disable-shared ' .
|
|
||||||
"--host={$this->builder->arch}-apple-darwin " .
|
|
||||||
"--target={$this->builder->arch}-apple-darwin " .
|
|
||||||
'--prefix= ' . // use prefix=/
|
|
||||||
"--libdir={$lib} && " .
|
|
||||||
'make clean && ' .
|
|
||||||
"make -j{$this->builder->concurrency} && " .
|
|
||||||
"make install DESTDIR={$destdir}"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\util\Patcher;
|
|
||||||
|
|
||||||
class libpng extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'libpng';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
// 不同架构的专属优化
|
|
||||||
$optimizations = match ($this->builder->arch) {
|
|
||||||
'x86_64' => '--enable-intel-sse ',
|
|
||||||
'arm64' => '--enable-arm-neon ',
|
|
||||||
default => '',
|
|
||||||
};
|
|
||||||
|
|
||||||
// patch configure
|
|
||||||
Patcher::patchUnixLibpng();
|
|
||||||
|
|
||||||
f_passthru(
|
|
||||||
$this->builder->set_x . ' && ' .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
"{$this->builder->configure_env} " .
|
|
||||||
'./configure ' .
|
|
||||||
"--host={$this->builder->gnu_arch}-apple-darwin " .
|
|
||||||
'--disable-shared ' .
|
|
||||||
'--enable-static ' .
|
|
||||||
'--enable-hardware-optimizations ' .
|
|
||||||
$optimizations .
|
|
||||||
'--prefix= && ' . // use prefix=/
|
|
||||||
'make clean && ' .
|
|
||||||
"make -j{$this->builder->concurrency} DEFAULT_INCLUDES='-I. -I" . BUILD_INCLUDE_PATH . "' LIBS= libpng16.la && " .
|
|
||||||
'make install-libLTLIBRARIES install-data-am DESTDIR=' . BUILD_ROOT_PATH . ' && ' .
|
|
||||||
'cd ' . BUILD_LIB_PATH . ' && ' .
|
|
||||||
'ln -sf libpng16.a libpng.a'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
class libssh2 extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'libssh2';
|
|
||||||
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
// lib:zlib
|
|
||||||
$enable_zlib = $this->builder->getLib('zlib') !== null ? 'ON' : 'OFF';
|
|
||||||
|
|
||||||
[$lib, $include, $destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
f_passthru(
|
|
||||||
$this->builder->set_x . ' && ' .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
'rm -rf build && ' .
|
|
||||||
'mkdir -p build && ' .
|
|
||||||
'cd build && ' .
|
|
||||||
"{$this->builder->configure_env} " . ' cmake ' .
|
|
||||||
// '--debug-find ' .
|
|
||||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
|
||||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
|
||||||
'-DBUILD_EXAMPLES=OFF ' .
|
|
||||||
'-DBUILD_TESTING=OFF ' .
|
|
||||||
"-DENABLE_ZLIB_COMPRESSION={$enable_zlib} " .
|
|
||||||
'-DCMAKE_INSTALL_PREFIX=/ ' .
|
|
||||||
"-DCMAKE_INSTALL_LIBDIR={$lib} " .
|
|
||||||
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
|
|
||||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
|
||||||
'.. && ' .
|
|
||||||
"cmake --build . -j {$this->builder->concurrency} --target libssh2 && " .
|
|
||||||
'make install DESTDIR="' . $destdir . '"'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* is a template library class for unix
|
|
||||||
*/
|
|
||||||
class libuv extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'libuv';
|
|
||||||
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
f_passthru(
|
|
||||||
$this->builder->set_x . ' && ' .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
"{$this->builder->configure_env} ./configure " .
|
|
||||||
'--enable-static --disable-shared ' .
|
|
||||||
'--prefix= && ' . // use prefix=/
|
|
||||||
'make clean && ' .
|
|
||||||
"make -j{$this->builder->concurrency} && " .
|
|
||||||
'make install DESTDIR=' . $destdir
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class libxml2 extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'libxml2';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
$enable_zlib = $this->builder->getLib('zlib') ? 'ON' : 'OFF';
|
|
||||||
$enable_icu = $this->builder->getLib('icu') ? 'ON' : 'OFF';
|
|
||||||
$enable_xz = $this->builder->getLib('xz') ? 'ON' : 'OFF';
|
|
||||||
|
|
||||||
[$lib, $include, $destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
f_passthru(
|
|
||||||
$this->builder->set_x . ' && ' .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
'rm -rf build && ' .
|
|
||||||
'mkdir -p build && ' .
|
|
||||||
'cd build && ' .
|
|
||||||
"{$this->builder->configure_env} " . ' cmake ' .
|
|
||||||
// '--debug-find ' .
|
|
||||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
|
||||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
|
||||||
'-DLIBXML2_WITH_ICONV=ON ' .
|
|
||||||
"-DLIBXML2_WITH_ZLIB={$enable_zlib} " .
|
|
||||||
"-DLIBXML2_WITH_ICU={$enable_icu} " .
|
|
||||||
"-DLIBXML2_WITH_LZMA={$enable_xz} " .
|
|
||||||
'-DLIBXML2_WITH_PYTHON=OFF ' .
|
|
||||||
'-DLIBXML2_WITH_PROGRAMS=OFF ' .
|
|
||||||
'-DLIBXML2_WITH_TESTS=OFF ' .
|
|
||||||
'-DCMAKE_INSTALL_PREFIX=/ ' .
|
|
||||||
"-DCMAKE_INSTALL_LIBDIR={$lib} " .
|
|
||||||
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
|
|
||||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
|
||||||
'.. && ' .
|
|
||||||
"cmake --build . -j {$this->builder->concurrency} && " .
|
|
||||||
'make install DESTDIR="' . $destdir . '"'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class libyaml extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'libyaml';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function build()
|
|
||||||
{
|
|
||||||
// prepare cmake/config.h.in
|
|
||||||
if (!is_file(SOURCE_PATH . '/libyaml/cmake/config.h.in')) {
|
|
||||||
f_mkdir(SOURCE_PATH . '/libyaml/cmake');
|
|
||||||
file_put_contents(
|
|
||||||
SOURCE_PATH . '/libyaml/cmake/config.h.in',
|
|
||||||
<<<'EOF'
|
|
||||||
#define YAML_VERSION_MAJOR @YAML_VERSION_MAJOR@
|
|
||||||
#define YAML_VERSION_MINOR @YAML_VERSION_MINOR@
|
|
||||||
#define YAML_VERSION_PATCH @YAML_VERSION_PATCH@
|
|
||||||
#define YAML_VERSION_STRING "@YAML_VERSION_STRING@"
|
|
||||||
EOF
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare yamlConfig.cmake.in
|
|
||||||
if (!is_file(SOURCE_PATH . '/libyaml/yamlConfig.cmake.in')) {
|
|
||||||
file_put_contents(
|
|
||||||
SOURCE_PATH . '/libyaml/yamlConfig.cmake.in',
|
|
||||||
<<<'EOF'
|
|
||||||
# Config file for the yaml library.
|
|
||||||
#
|
|
||||||
# It defines the following variables:
|
|
||||||
# yaml_LIBRARIES - libraries to link against
|
|
||||||
|
|
||||||
@PACKAGE_INIT@
|
|
||||||
|
|
||||||
set_and_check(yaml_TARGETS "@PACKAGE_CONFIG_DIR_CONFIG@/yamlTargets.cmake")
|
|
||||||
|
|
||||||
if(NOT yaml_TARGETS_IMPORTED)
|
|
||||||
set(yaml_TARGETS_IMPORTED 1)
|
|
||||||
include(${yaml_TARGETS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(yaml_LIBRARIES yaml)
|
|
||||||
|
|
||||||
EOF
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
[$lib, $include, $destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
f_passthru(
|
|
||||||
$this->builder->set_x . ' && ' .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
'rm -rf build && ' .
|
|
||||||
'mkdir -p build && ' .
|
|
||||||
'cd build && ' .
|
|
||||||
"{$this->builder->configure_env} " . ' cmake ' .
|
|
||||||
// '--debug-find ' .
|
|
||||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
|
||||||
'-DBUILD_TESTING=OFF ' .
|
|
||||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
|
||||||
'-DCMAKE_INSTALL_PREFIX=/ ' .
|
|
||||||
"-DCMAKE_INSTALL_LIBDIR={$lib} " .
|
|
||||||
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
|
|
||||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
|
||||||
'.. && ' .
|
|
||||||
"make -j{$this->builder->concurrency} && " .
|
|
||||||
'make install DESTDIR=' . $destdir
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
class libzip extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'libzip';
|
|
||||||
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
$extra = '';
|
|
||||||
// lib:zlib
|
|
||||||
$zlib = $this->builder->getLib('zlib');
|
|
||||||
if ($zlib instanceof MacOSLibraryBase) {
|
|
||||||
$extra .= '-DZLIB_LIBRARY="' . $zlib->getStaticLibFiles(style: 'cmake') . '" ' .
|
|
||||||
'-DZLIB_INCLUDE_DIR=' . BUILD_INCLUDE_PATH . ' ';
|
|
||||||
}
|
|
||||||
// lib:bzip2
|
|
||||||
$libbzip2 = $this->builder->getLib('bzip2');
|
|
||||||
if ($libbzip2 instanceof MacOSLibraryBase) {
|
|
||||||
$extra .= '-DENABLE_BZIP2=ON ' .
|
|
||||||
'-DBZIP2_LIBRARIES="' . $libbzip2->getStaticLibFiles(style: 'cmake') . '" ' .
|
|
||||||
'-DBZIP2_INCLUDE_DIR=' . BUILD_INCLUDE_PATH . ' ';
|
|
||||||
} else {
|
|
||||||
$extra .= '-DENABLE_BZIP2=OFF ';
|
|
||||||
}
|
|
||||||
// lib:xz
|
|
||||||
$xz = $this->builder->getLib('xz');
|
|
||||||
if ($xz instanceof MacOSLibraryBase) {
|
|
||||||
$extra .= '-DENABLE_LZMA=ON ' .
|
|
||||||
'-DLIBLZMA_LIBRARY="' . $xz->getStaticLibFiles(style: 'cmake') . '" ' .
|
|
||||||
'-DLIBLZMA_INCLUDE_DIR=' . BUILD_INCLUDE_PATH . ' ';
|
|
||||||
} else {
|
|
||||||
$extra .= '-DENABLE_LZMA=OFF ';
|
|
||||||
}
|
|
||||||
// lib:zstd
|
|
||||||
$libzstd = $this->builder->getLib('zstd');
|
|
||||||
if ($libzstd instanceof MacOSLibraryBase) {
|
|
||||||
$extra .= '-DENABLE_ZSTD=ON ' .
|
|
||||||
'-DZstd_LIBRARY="' . $libzstd->getStaticLibFiles(style: 'cmake') . '" ' .
|
|
||||||
'-DZstd_INCLUDE_DIR="' . BUILD_INCLUDE_PATH . '" ';
|
|
||||||
} else {
|
|
||||||
$extra .= '-DENABLE_ZSTD=OFF ';
|
|
||||||
}
|
|
||||||
// lib:openssl
|
|
||||||
$libopenssl = $this->builder->getLib('openssl');
|
|
||||||
if ($libopenssl instanceof MacOSLibraryBase) {
|
|
||||||
$extra .= '-DENABLE_OPENSSL=ON ' .
|
|
||||||
'-DOpenSSL_LIBRARY="' . $libopenssl->getStaticLibFiles(style: 'cmake') . '" ' .
|
|
||||||
'-DOpenSSL_INCLUDE_DIR="' . BUILD_INCLUDE_PATH . '" ';
|
|
||||||
} else {
|
|
||||||
$extra .= '-DENABLE_OPENSSL=OFF ';
|
|
||||||
}
|
|
||||||
|
|
||||||
[$lib, $include, $destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
f_passthru(
|
|
||||||
$this->builder->set_x . ' && ' .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
'rm -rf build && ' .
|
|
||||||
'mkdir -p build && ' .
|
|
||||||
'cd build && ' .
|
|
||||||
"{$this->builder->configure_env} " . ' cmake ' .
|
|
||||||
// '--debug-find ' .
|
|
||||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
|
||||||
'-DENABLE_GNUTLS=OFF ' .
|
|
||||||
'-DENABLE_MBEDTLS=OFF ' .
|
|
||||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
|
||||||
'-DBUILD_DOC=OFF ' .
|
|
||||||
'-DBUILD_EXAMPLES=OFF ' .
|
|
||||||
'-DBUILD_REGRESS=OFF ' .
|
|
||||||
'-DBUILD_TOOLS=OFF ' .
|
|
||||||
$extra .
|
|
||||||
'-DCMAKE_INSTALL_PREFIX=/ ' .
|
|
||||||
"-DCMAKE_INSTALL_LIBDIR={$lib} " .
|
|
||||||
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
|
|
||||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
|
||||||
'.. && ' .
|
|
||||||
"make -j{$this->builder->concurrency} && " .
|
|
||||||
'make install DESTDIR=' . $destdir
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
class nghttp2 extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'nghttp2';
|
|
||||||
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
$args = $this->builder->makeAutoconfArgs(static::NAME, [
|
|
||||||
'zlib' => null,
|
|
||||||
'openssl' => null,
|
|
||||||
'libxml2' => null,
|
|
||||||
'libev' => null,
|
|
||||||
'libcares' => null,
|
|
||||||
'libngtcp2' => null,
|
|
||||||
'libnghttp3' => null,
|
|
||||||
'libbpf' => null,
|
|
||||||
'libevent-openssl' => null,
|
|
||||||
'jansson' => null,
|
|
||||||
'jemalloc' => null,
|
|
||||||
'systemd' => null,
|
|
||||||
'cunit' => null,
|
|
||||||
]);
|
|
||||||
|
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
f_passthru(
|
|
||||||
$this->builder->set_x . ' && ' .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
"{$this->builder->configure_env} " . ' ./configure ' .
|
|
||||||
'--enable-static ' .
|
|
||||||
'--disable-shared ' .
|
|
||||||
"--host={$this->builder->gnu_arch}-apple-darwin " .
|
|
||||||
'--enable-lib-only ' .
|
|
||||||
'--with-boost=no ' .
|
|
||||||
$args . ' ' .
|
|
||||||
'--prefix= && ' . // use prefix=/
|
|
||||||
'make clean && ' .
|
|
||||||
"make -j{$this->builder->concurrency} && " .
|
|
||||||
"make install DESTDIR={$destdir}"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
class onig extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'onig';
|
|
||||||
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
f_passthru(
|
|
||||||
$this->builder->set_x . ' && ' .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
"{$this->builder->configure_env} " . ' ./configure ' .
|
|
||||||
'--enable-static ' .
|
|
||||||
'--disable-shared ' .
|
|
||||||
"--host={$this->builder->arch}-apple-darwin " .
|
|
||||||
'--prefix= && ' . // use prefix=/
|
|
||||||
'make clean && ' .
|
|
||||||
"make -j{$this->builder->concurrency} && " .
|
|
||||||
'make install DESTDIR=' . $destdir
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
class openssl extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'openssl';
|
|
||||||
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
[$lib,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
// lib:zlib
|
|
||||||
$extra = '';
|
|
||||||
$ex_lib = '';
|
|
||||||
$zlib = $this->builder->getLib('zlib');
|
|
||||||
if ($zlib instanceof MacOSLibraryBase) {
|
|
||||||
$extra = 'zlib';
|
|
||||||
$ex_lib = trim($zlib->getStaticLibFiles() . ' ' . $ex_lib);
|
|
||||||
}
|
|
||||||
|
|
||||||
f_passthru(
|
|
||||||
$this->builder->set_x . ' && ' .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
"{$this->builder->configure_env} ./Configure no-shared {$extra} " .
|
|
||||||
'--prefix=/ ' . // use prefix=/
|
|
||||||
"--libdir={$lib} " .
|
|
||||||
" darwin64-{$this->builder->arch}-cc && " .
|
|
||||||
'make clean && ' .
|
|
||||||
"make -j{$this->builder->concurrency} CNF_EX_LIBS=\"{$ex_lib}\" && " .
|
|
||||||
'make install_sw DESTDIR=' . $destdir
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
class sqlite extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'sqlite';
|
|
||||||
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
f_passthru(
|
|
||||||
$this->builder->set_x . ' && ' .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
"{$this->builder->configure_env} ./configure " .
|
|
||||||
'--enable-static --disable-shared ' .
|
|
||||||
'--prefix= && ' . // use prefix=/
|
|
||||||
'make clean && ' .
|
|
||||||
"make -j{$this->builder->concurrency} && " .
|
|
||||||
'make install DESTDIR=' . $destdir
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
class xz extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'xz';
|
|
||||||
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
f_passthru(
|
|
||||||
$this->builder->set_x . ' && ' .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
'autoreconf -i --force && ' .
|
|
||||||
"{$this->builder->configure_env} ./configure " .
|
|
||||||
'--enable-static ' .
|
|
||||||
'--disable-shared ' .
|
|
||||||
"--host={$this->builder->gnu_arch}-apple-darwin " .
|
|
||||||
'--disable-xz ' .
|
|
||||||
'--disable-xzdec ' .
|
|
||||||
'--disable-lzmadec ' .
|
|
||||||
'--disable-lzmainfo ' .
|
|
||||||
'--disable-scripts ' .
|
|
||||||
'--disable-doc ' .
|
|
||||||
'--with-libiconv ' .
|
|
||||||
'--prefix= && ' . // use prefix=/
|
|
||||||
'make clean && ' .
|
|
||||||
"make -j{$this->builder->concurrency} && " .
|
|
||||||
'make install DESTDIR=' . $destdir
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
class zlib extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'zlib';
|
|
||||||
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
f_passthru(
|
|
||||||
$this->builder->set_x . ' && ' .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
"{$this->builder->configure_env} ./configure " .
|
|
||||||
'--static ' .
|
|
||||||
'--prefix= && ' . // use prefix=/
|
|
||||||
'make clean && ' .
|
|
||||||
"make -j{$this->builder->concurrency} && " .
|
|
||||||
'make install DESTDIR=' . $destdir
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
class zstd extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
public const NAME = 'zstd';
|
|
||||||
|
|
||||||
protected function build()
|
|
||||||
{
|
|
||||||
f_passthru(
|
|
||||||
$this->builder->set_x . ' && ' .
|
|
||||||
"cd {$this->source_dir} && " .
|
|
||||||
"make {$this->builder->configure_env} PREFIX='" . BUILD_ROOT_PATH . "' clean" . ' && ' .
|
|
||||||
"make -j{$this->builder->concurrency} " .
|
|
||||||
"{$this->builder->configure_env} " .
|
|
||||||
"PREFIX='" . BUILD_ROOT_PATH . "' " .
|
|
||||||
'-C lib libzstd.a CPPFLAGS_STATLIB=-DZSTD_MULTITHREAD && ' .
|
|
||||||
'cp lib/libzstd.a ' . BUILD_LIB_PATH . ' && ' .
|
|
||||||
'cp lib/zdict.h lib/zstd_errors.h lib/zstd.h ' . BUILD_INCLUDE_PATH
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\traits;
|
|
||||||
|
|
||||||
trait LibraryTrait
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\traits;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 仅供 Command 使用,如果使用了该 Trait,则在执行对应命令时不打印 motd
|
|
||||||
*/
|
|
||||||
trait NoMotdTrait
|
|
||||||
{
|
|
||||||
protected bool $no_motd = true;
|
|
||||||
}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\traits;
|
|
||||||
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\store\FileSystem;
|
|
||||||
|
|
||||||
trait UnixBuilderTrait
|
|
||||||
{
|
|
||||||
/** @var string 设置的命令前缀,设置为 set -x 可以在终端打印命令 */
|
|
||||||
public string $set_x = 'set -x';
|
|
||||||
|
|
||||||
/** @var string C 编译器命令 */
|
|
||||||
public string $cc;
|
|
||||||
|
|
||||||
/** @var string C++ 编译器命令 */
|
|
||||||
public string $cxx;
|
|
||||||
|
|
||||||
/** @var string cflags 参数 */
|
|
||||||
public string $arch_c_flags;
|
|
||||||
|
|
||||||
/** @var string C++ flags 参数 */
|
|
||||||
public string $arch_cxx_flags;
|
|
||||||
|
|
||||||
/** @var string cmake toolchain file */
|
|
||||||
public string $cmake_toolchain_file;
|
|
||||||
|
|
||||||
/** @var string configure 环境依赖的变量 */
|
|
||||||
public string $configure_env;
|
|
||||||
|
|
||||||
public function getAllStaticLibFiles(): array
|
|
||||||
{
|
|
||||||
$libs = [];
|
|
||||||
|
|
||||||
// reorder libs
|
|
||||||
foreach ($this->libs as $lib) {
|
|
||||||
foreach ($lib->getDependencies() as $dep) {
|
|
||||||
$libs[] = $dep;
|
|
||||||
}
|
|
||||||
$libs[] = $lib;
|
|
||||||
}
|
|
||||||
|
|
||||||
$libFiles = [];
|
|
||||||
$libNames = [];
|
|
||||||
// merge libs
|
|
||||||
foreach ($libs as $lib) {
|
|
||||||
if (!in_array($lib::NAME, $libNames, true)) {
|
|
||||||
$libNames[] = $lib::NAME;
|
|
||||||
array_unshift($libFiles, ...$lib->getStaticLibs());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return array_map(fn ($x) => realpath(BUILD_LIB_PATH . "/{$x}"), $libFiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function sanityCheck(int $build_micro_rule): void
|
|
||||||
{
|
|
||||||
logger()->info('running sanity check');
|
|
||||||
if ($build_micro_rule !== BUILD_MICRO_ONLY) {
|
|
||||||
[$ret, $output] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -r "echo \"hello\";"');
|
|
||||||
if ($ret !== 0 || trim(implode('', $output)) !== 'hello') {
|
|
||||||
throw new RuntimeException('cli failed sanity check');
|
|
||||||
}
|
|
||||||
foreach ($this->exts as $ext) {
|
|
||||||
logger()->debug('testing ext: ' . $ext->getName());
|
|
||||||
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri ' . $ext->getName(), false);
|
|
||||||
if ($ret !== 0) {
|
|
||||||
throw new RuntimeException('extension ' . $ext->getName() . ' failed compile check');
|
|
||||||
}
|
|
||||||
if (file_exists(ROOT_DIR . '/src/globals/tests/' . $ext->getName() . '.php')) {
|
|
||||||
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php ' . ROOT_DIR . '/src/globals/tests/' . $ext->getName() . '.php');
|
|
||||||
if ($ret !== 0) {
|
|
||||||
throw new RuntimeException('extension ' . $ext->getName() . ' failed sanity check');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($build_micro_rule !== BUILD_MICRO_NONE) {
|
|
||||||
if (file_exists(SOURCE_PATH . '/hello.exe')) {
|
|
||||||
@unlink(SOURCE_PATH . '/hello.exe');
|
|
||||||
}
|
|
||||||
file_put_contents(
|
|
||||||
SOURCE_PATH . '/hello.exe',
|
|
||||||
file_get_contents(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx') .
|
|
||||||
'<?php echo "hello";'
|
|
||||||
);
|
|
||||||
chmod(SOURCE_PATH . '/hello.exe', 0755);
|
|
||||||
[$ret, $output2] = shell()->execWithResult(SOURCE_PATH . '/hello.exe');
|
|
||||||
if ($ret !== 0 || trim($out = implode('', $output2)) !== 'hello') {
|
|
||||||
throw new RuntimeException('micro failed sanity check, ret[' . $ret . '], out[' . ($out ?? 'NULL') . ']');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将编译好的二进制文件发布到 buildroot
|
|
||||||
*
|
|
||||||
* @param int $type 发布类型
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public function deployBinary(int $type): bool
|
|
||||||
{
|
|
||||||
$src = match ($type) {
|
|
||||||
BUILD_TYPE_CLI => SOURCE_PATH . '/php-src/sapi/cli/php',
|
|
||||||
BUILD_TYPE_MICRO => SOURCE_PATH . '/php-src/sapi/micro/micro.sfx',
|
|
||||||
default => throw new RuntimeException('Deployment does not accept type ' . $type),
|
|
||||||
};
|
|
||||||
logger()->info('Deploying ' . ($type === BUILD_TYPE_CLI ? 'cli' : 'micro') . ' file');
|
|
||||||
FileSystem::createDir(BUILD_ROOT_PATH . '/bin');
|
|
||||||
shell()->exec('cp ' . escapeshellarg($src) . ' ' . escapeshellarg(BUILD_ROOT_PATH . '/bin/'));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清理编译好的文件
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function cleanMake(): void
|
|
||||||
{
|
|
||||||
logger()->info('cleaning up');
|
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')->exec('make clean');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\traits;
|
|
||||||
|
|
||||||
use SPC\builder\LibraryBase;
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\store\FileSystem;
|
|
||||||
|
|
||||||
trait UnixLibraryTrait
|
|
||||||
{
|
|
||||||
use LibraryTrait;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true): string
|
|
||||||
{
|
|
||||||
$libs = [$this];
|
|
||||||
if ($recursive) {
|
|
||||||
array_unshift($libs, ...array_values($this->getDependencies(recursive: true)));
|
|
||||||
}
|
|
||||||
|
|
||||||
$sep = match ($style) {
|
|
||||||
'autoconf' => ' ',
|
|
||||||
'cmake' => ';',
|
|
||||||
default => throw new RuntimeException('style only support autoconf and cmake'),
|
|
||||||
};
|
|
||||||
$ret = [];
|
|
||||||
/** @var LibraryBase $lib */
|
|
||||||
foreach ($libs as $lib) {
|
|
||||||
$libFiles = [];
|
|
||||||
foreach ($lib->getStaticLibs() as $name) {
|
|
||||||
$name = str_replace(' ', '\ ', FileSystem::convertPath(BUILD_LIB_PATH . "/{$name}"));
|
|
||||||
$name = str_replace('"', '\"', $name);
|
|
||||||
$libFiles[] = $name;
|
|
||||||
}
|
|
||||||
array_unshift($ret, implode($sep, $libFiles));
|
|
||||||
}
|
|
||||||
return implode($sep, $ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function makeAutoconfEnv(string $prefix = null): string
|
|
||||||
{
|
|
||||||
if ($prefix === null) {
|
|
||||||
$prefix = str_replace('-', '_', strtoupper(static::NAME));
|
|
||||||
}
|
|
||||||
return $prefix . '_CFLAGS="-I' . BUILD_INCLUDE_PATH . '" ' .
|
|
||||||
$prefix . '_LIBS="' . $this->getStaticLibFiles() . '"';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\traits;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unix 系统的工具函数 Trait,适用于 Linux、macOS
|
|
||||||
*/
|
|
||||||
trait UnixSystemUtilTrait
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 生成 toolchain.cmake,用于 cmake 构建
|
|
||||||
*
|
|
||||||
* @param string $os 操作系统代号
|
|
||||||
* @param string $target_arch 目标架构
|
|
||||||
* @param string $cflags CFLAGS 参数
|
|
||||||
* @param null|string $cc CC 参数(默认空)
|
|
||||||
* @param null|string $cxx CXX 参数(默认空)
|
|
||||||
*/
|
|
||||||
public static function makeCmakeToolchainFile(
|
|
||||||
string $os,
|
|
||||||
string $target_arch,
|
|
||||||
string $cflags,
|
|
||||||
?string $cc = null,
|
|
||||||
?string $cxx = null
|
|
||||||
): string {
|
|
||||||
logger()->debug("making cmake tool chain file for {$os} {$target_arch} with CFLAGS='{$cflags}'");
|
|
||||||
$root = BUILD_ROOT_PATH;
|
|
||||||
$ccLine = '';
|
|
||||||
if ($cc) {
|
|
||||||
$ccLine = 'SET(CMAKE_C_COMPILER ' . self::findCommand($cc) . ')';
|
|
||||||
}
|
|
||||||
$cxxLine = '';
|
|
||||||
if ($cxx) {
|
|
||||||
$cxxLine = 'SET(CMAKE_CXX_COMPILER ' . self::findCommand($cxx) . ')';
|
|
||||||
}
|
|
||||||
$toolchain = <<<CMAKE
|
|
||||||
SET(CMAKE_SYSTEM_NAME {$os})
|
|
||||||
SET(CMAKE_SYSTEM_PROCESSOR {$target_arch})
|
|
||||||
{$ccLine}
|
|
||||||
{$cxxLine}
|
|
||||||
SET(CMAKE_C_FLAGS "{$cflags}")
|
|
||||||
SET(CMAKE_CXX_FLAGS "{$cflags}")
|
|
||||||
SET(CMAKE_FIND_ROOT_PATH "{$root}")
|
|
||||||
CMAKE;
|
|
||||||
// 有时候系统的 cmake 找不到 ar 命令,真奇怪
|
|
||||||
if (PHP_OS_FAMILY === 'Linux') {
|
|
||||||
$toolchain .= "\nSET(CMAKE_AR \"ar\")";
|
|
||||||
}
|
|
||||||
file_put_contents(SOURCE_PATH . '/toolchain.cmake', $toolchain);
|
|
||||||
return realpath(SOURCE_PATH . '/toolchain.cmake');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $name 命令名称
|
|
||||||
* @param array $paths 寻找的目标路径(如果不传入,则使用环境变量 PATH)
|
|
||||||
* @return null|string 找到了返回命令路径,找不到返回 null
|
|
||||||
*/
|
|
||||||
public static function findCommand(string $name, array $paths = []): ?string
|
|
||||||
{
|
|
||||||
if (!$paths) {
|
|
||||||
$paths = explode(PATH_SEPARATOR, getenv('PATH'));
|
|
||||||
}
|
|
||||||
foreach ($paths as $path) {
|
|
||||||
if (file_exists($path . DIRECTORY_SEPARATOR . $name)) {
|
|
||||||
return $path . DIRECTORY_SEPARATOR . $name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\command;
|
|
||||||
|
|
||||||
use Psr\Log\LogLevel;
|
|
||||||
use SPC\ConsoleApplication;
|
|
||||||
use Symfony\Component\Console\Command\Command;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
use ZM\Logger\ConsoleLogger;
|
|
||||||
|
|
||||||
abstract class BaseCommand extends Command
|
|
||||||
{
|
|
||||||
public function __construct(string $name = null)
|
|
||||||
{
|
|
||||||
parent::__construct($name);
|
|
||||||
$this->addOption('debug', null, null, 'Enable debug mode');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function initialize(InputInterface $input, OutputInterface $output)
|
|
||||||
{
|
|
||||||
// 注册全局错误处理器
|
|
||||||
set_error_handler(static function ($error_no, $error_msg, $error_file, $error_line) {
|
|
||||||
$tips = [
|
|
||||||
E_WARNING => ['PHP Warning: ', 'warning'],
|
|
||||||
E_NOTICE => ['PHP Notice: ', 'notice'],
|
|
||||||
E_USER_ERROR => ['PHP Error: ', 'error'],
|
|
||||||
E_USER_WARNING => ['PHP Warning: ', 'warning'],
|
|
||||||
E_USER_NOTICE => ['PHP Notice: ', 'notice'],
|
|
||||||
E_STRICT => ['PHP Strict: ', 'notice'],
|
|
||||||
E_RECOVERABLE_ERROR => ['PHP Recoverable Error: ', 'error'],
|
|
||||||
E_DEPRECATED => ['PHP Deprecated: ', 'notice'],
|
|
||||||
E_USER_DEPRECATED => ['PHP User Deprecated: ', 'notice'],
|
|
||||||
];
|
|
||||||
$level_tip = $tips[$error_no] ?? ['PHP Unknown: ', 'error'];
|
|
||||||
$error = $level_tip[0] . $error_msg . ' in ' . $error_file . ' on ' . $error_line;
|
|
||||||
logger()->{$level_tip[1]}($error);
|
|
||||||
// 如果 return false 则错误会继续递交给 PHP 标准错误处理
|
|
||||||
return true;
|
|
||||||
}, E_ALL | E_STRICT);
|
|
||||||
if ($input->getOption('debug')) {
|
|
||||||
global $ob_logger;
|
|
||||||
$ob_logger = new ConsoleLogger(LogLevel::DEBUG);
|
|
||||||
define('DEBUG_MODE', true);
|
|
||||||
}
|
|
||||||
$version = ConsoleApplication::VERSION;
|
|
||||||
if (!isset($this->no_motd)) {
|
|
||||||
echo " _ _ _ _
|
|
||||||
___| |_ __ _| |_(_) ___ _ __ | |__ _ __
|
|
||||||
/ __| __/ _` | __| |/ __|____| '_ \\| '_ \\| '_ \\
|
|
||||||
\\__ \\ || (_| | |_| | (_|_____| |_) | | | | |_) |
|
|
||||||
|___/\\__\\__,_|\\__|_|\\___| | .__/|_| |_| .__/ v{$version}
|
|
||||||
|_| |_|
|
|
||||||
";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\command;
|
|
||||||
|
|
||||||
use SPC\builder\BuilderProvider;
|
|
||||||
use SPC\exception\ExceptionHandler;
|
|
||||||
use SPC\util\DependencyUtil;
|
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
|
|
||||||
/** @noinspection PhpUnused */
|
|
||||||
class BuildCliCommand extends BuildCommand
|
|
||||||
{
|
|
||||||
protected static $defaultName = 'build';
|
|
||||||
|
|
||||||
public function configure()
|
|
||||||
{
|
|
||||||
$this->setDescription('Build CLI binary');
|
|
||||||
$this->addArgument('extensions', InputArgument::REQUIRED, 'The extensions will be compiled, comma separated');
|
|
||||||
$this->addOption('with-libs', null, InputOption::VALUE_REQUIRED, 'add additional libraries, comma separated', '');
|
|
||||||
$this->addOption('build-micro', null, null, 'build micro only');
|
|
||||||
$this->addOption('build-all', null, null, 'build both cli and micro');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute(InputInterface $input, OutputInterface $output): int
|
|
||||||
{
|
|
||||||
// 从参数中获取要编译的 libraries,并转换为数组
|
|
||||||
$libraries = array_map('trim', array_filter(explode(',', $input->getOption('with-libs'))));
|
|
||||||
// 从参数中获取要编译的 extensions,并转换为数组
|
|
||||||
$extensions = array_map('trim', array_filter(explode(',', $input->getArgument('extensions'))));
|
|
||||||
|
|
||||||
define('BUILD_ALL_STATIC', true);
|
|
||||||
|
|
||||||
if ($input->getOption('build-all')) {
|
|
||||||
$rule = BUILD_MICRO_BOTH;
|
|
||||||
logger()->info('Builder will build php-cli and phpmicro SAPI');
|
|
||||||
} elseif ($input->getOption('build-micro')) {
|
|
||||||
$rule = BUILD_MICRO_ONLY;
|
|
||||||
logger()->info('Builder will build phpmicro SAPI');
|
|
||||||
} else {
|
|
||||||
$rule = BUILD_MICRO_NONE;
|
|
||||||
logger()->info('Builder will build php-cli SAPI');
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// 构建对象
|
|
||||||
$builder = BuilderProvider::makeBuilderByInput($input);
|
|
||||||
// 根据提供的扩展列表获取依赖库列表并编译
|
|
||||||
[$extensions, $libraries, $not_included] = DependencyUtil::getExtLibsByDeps($extensions, $libraries);
|
|
||||||
|
|
||||||
logger()->info('Enabled extensions: ' . implode(', ', $extensions));
|
|
||||||
logger()->info('Required libraries: ' . implode(', ', $libraries));
|
|
||||||
if (!empty($not_included)) {
|
|
||||||
logger()->warning('some extensions will be enabled due to dependencies: ' . implode(',', $not_included));
|
|
||||||
}
|
|
||||||
sleep(2);
|
|
||||||
// 编译和检查库是否完整
|
|
||||||
$builder->buildLibs($libraries);
|
|
||||||
// 执行扩展检测
|
|
||||||
$builder->proveExts($extensions);
|
|
||||||
// 构建
|
|
||||||
$builder->buildPHP($rule, $input->getOption('bloat'));
|
|
||||||
// 统计时间
|
|
||||||
$time = round(microtime(true) - START_TIME, 3);
|
|
||||||
logger()->info('Build complete, used ' . $time . ' s !');
|
|
||||||
if ($rule !== BUILD_MICRO_ONLY) {
|
|
||||||
logger()->info('Static php binary path: ' . BUILD_ROOT_PATH . '/bin/php');
|
|
||||||
}
|
|
||||||
if ($rule !== BUILD_MICRO_NONE) {
|
|
||||||
logger()->info('phpmicro binary path: ' . BUILD_ROOT_PATH . '/bin/micro.sfx');
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
if ($input->getOption('debug')) {
|
|
||||||
ExceptionHandler::getInstance()->handle($e);
|
|
||||||
} else {
|
|
||||||
logger()->critical('Build failed with ' . get_class($e) . ': ' . $e->getMessage());
|
|
||||||
logger()->critical('Please check with --debug option to see more details.');
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\command;
|
|
||||||
|
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
|
||||||
|
|
||||||
abstract class BuildCommand extends BaseCommand
|
|
||||||
{
|
|
||||||
public function __construct(string $name = null)
|
|
||||||
{
|
|
||||||
parent::__construct($name);
|
|
||||||
|
|
||||||
// 根据运行的操作系统分配允许不同的命令行参数,Windows 需要额外的 VS 和 SDK等,*nix 需要提供架构
|
|
||||||
switch (PHP_OS_FAMILY) {
|
|
||||||
case 'Windows':
|
|
||||||
$this->addOption('with-sdk-binary-dir', null, InputOption::VALUE_REQUIRED, 'path to binary sdk');
|
|
||||||
$this->addOption('vs-ver', null, InputOption::VALUE_REQUIRED, 'vs version, e.g. "17" for Visual Studio 2022');
|
|
||||||
$this->addOption('arch', null, InputOption::VALUE_REQUIRED, 'architecture, "x64" or "arm64"', 'x64');
|
|
||||||
break;
|
|
||||||
case 'Linux':
|
|
||||||
$this->addOption('no-system-static', null, null, 'do not use system static libraries');
|
|
||||||
// no break
|
|
||||||
case 'Darwin':
|
|
||||||
$this->addOption('cc', null, InputOption::VALUE_REQUIRED, 'C compiler');
|
|
||||||
$this->addOption('cxx', null, InputOption::VALUE_REQUIRED, 'C++ compiler');
|
|
||||||
$this->addOption('arch', null, InputOption::VALUE_REQUIRED, 'architecture', php_uname('m'));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 是否在编译 make 前清除旧的文件
|
|
||||||
$this->addOption('with-clean', null, null, 'fresh build, `make clean` before `make`');
|
|
||||||
// 是否采用强制链接,让链接器强制加载静态库文件
|
|
||||||
$this->addOption('bloat', null, null, 'add all libraries into binary');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\command;
|
|
||||||
|
|
||||||
use SPC\builder\BuilderProvider;
|
|
||||||
use SPC\exception\ExceptionHandler;
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
|
|
||||||
/** @noinspection PhpUnused */
|
|
||||||
class BuildLibsCommand extends BuildCommand
|
|
||||||
{
|
|
||||||
protected static $defaultName = 'build:libs';
|
|
||||||
|
|
||||||
public function configure()
|
|
||||||
{
|
|
||||||
$this->setDescription('Build dependencies');
|
|
||||||
$this->addArgument('libraries', InputArgument::REQUIRED, 'The libraries will be compiled, comma separated');
|
|
||||||
$this->addOption('clean', null, null, 'Clean old download cache and source before fetch');
|
|
||||||
$this->addOption('all', 'A', null, 'Build all libs that static-php-cli needed');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function initialize(InputInterface $input, OutputInterface $output)
|
|
||||||
{
|
|
||||||
// --all 等于 ""
|
|
||||||
if ($input->getOption('all')) {
|
|
||||||
$input->setArgument('libraries', '');
|
|
||||||
}
|
|
||||||
parent::initialize($input, $output);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public function execute(InputInterface $input, OutputInterface $output): int
|
|
||||||
{
|
|
||||||
// 从参数中获取要编译的 libraries,并转换为数组
|
|
||||||
$libraries = array_map('trim', array_filter(explode(',', $input->getArgument('libraries'))));
|
|
||||||
|
|
||||||
// 删除旧资源
|
|
||||||
if ($input->getOption('clean')) {
|
|
||||||
logger()->warning('You are doing some operations that not recoverable: removing directories below');
|
|
||||||
logger()->warning(BUILD_ROOT_PATH);
|
|
||||||
logger()->warning('I will remove these dir after you press [Enter] !');
|
|
||||||
echo 'Confirm operation? [Yes] ';
|
|
||||||
fgets(STDIN);
|
|
||||||
if (PHP_OS_FAMILY === 'Windows') {
|
|
||||||
f_passthru('rmdir /s /q ' . BUILD_ROOT_PATH);
|
|
||||||
} else {
|
|
||||||
f_passthru('rm -rf ' . BUILD_ROOT_PATH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 构建对象
|
|
||||||
$builder = BuilderProvider::makeBuilderByInput($input);
|
|
||||||
// 只编译 library 的情况下,标记
|
|
||||||
$builder->setLibsOnly();
|
|
||||||
// 编译和检查库完整
|
|
||||||
$builder->buildLibs($libraries);
|
|
||||||
|
|
||||||
$time = round(microtime(true) - START_TIME, 3);
|
|
||||||
logger()->info('Build libs complete, used ' . $time . ' s !');
|
|
||||||
return 0;
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
if ($input->getOption('debug')) {
|
|
||||||
ExceptionHandler::getInstance()->handle($e);
|
|
||||||
} else {
|
|
||||||
logger()->critical('Build failed with ' . get_class($e) . ': ' . $e->getMessage());
|
|
||||||
logger()->critical('Please check with --debug option to see more details.');
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\command;
|
|
||||||
|
|
||||||
use CliHelper\Tools\ArgFixer;
|
|
||||||
use CliHelper\Tools\DataProvider;
|
|
||||||
use CliHelper\Tools\SeekableArrayIterator;
|
|
||||||
use Symfony\Component\Console\Helper\ProgressBar;
|
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
|
|
||||||
/** @noinspection PhpUnused */
|
|
||||||
class DeployCommand extends BaseCommand
|
|
||||||
{
|
|
||||||
protected static $defaultName = 'deploy';
|
|
||||||
|
|
||||||
public function configure()
|
|
||||||
{
|
|
||||||
$this->setDescription('Deploy static-php-cli self to an .phar application');
|
|
||||||
$this->addArgument('target', InputArgument::OPTIONAL, 'The file or directory to pack.');
|
|
||||||
$this->addOption('auto-phar-fix', null, InputOption::VALUE_NONE, 'Automatically fix ini option.');
|
|
||||||
$this->addOption('overwrite', 'W', InputOption::VALUE_NONE, 'Overwrite existing files.');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute(InputInterface $input, OutputInterface $output): int
|
|
||||||
{
|
|
||||||
// 第一阶段流程:如果没有写path,将会提示输入要打包的path
|
|
||||||
$prompt = new ArgFixer($input, $output);
|
|
||||||
// 首先得确认是不是关闭了readonly模式
|
|
||||||
if (ini_get('phar.readonly') == 1) {
|
|
||||||
if ($input->getOption('auto-phar-fix')) {
|
|
||||||
$ask = true;
|
|
||||||
} else {
|
|
||||||
$ask = $prompt->requireBool('<comment>pack command needs "phar.readonly" = "Off" !</comment>' . PHP_EOL . 'If you want to automatically set it and continue, just Enter', true);
|
|
||||||
}
|
|
||||||
if ($ask) {
|
|
||||||
global $argv;
|
|
||||||
$args = array_merge(['-d', 'phar.readonly=0'], $_SERVER['argv']);
|
|
||||||
if (function_exists('pcntl_exec')) {
|
|
||||||
$output->writeln('<info>Changing to phar.readonly=0 mode ...</info>');
|
|
||||||
if (pcntl_exec(PHP_BINARY, $args) === false) {
|
|
||||||
throw new \PharException('切换到读写模式失败,请检查环境。');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$output->writeln('<info>Now running command in child process.</info>');
|
|
||||||
passthru(PHP_BINARY . ' -d phar.readonly=0 ' . implode(' ', $argv), $retcode);
|
|
||||||
exit($retcode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 获取路径
|
|
||||||
$path = WORKING_DIR;
|
|
||||||
// 如果是目录,则将目录下的所有文件打包
|
|
||||||
$phar_path = $prompt->requireArgument('target', 'Please input the phar target filename', 'static-php-cli.phar');
|
|
||||||
|
|
||||||
if (DataProvider::isRelativePath($phar_path)) {
|
|
||||||
$phar_path = '/tmp/' . $phar_path;
|
|
||||||
}
|
|
||||||
if (file_exists($phar_path)) {
|
|
||||||
$ask = $input->getOption('overwrite') ? true : $prompt->requireBool('<comment>The file "' . $phar_path . '" already exists, do you want to overwrite it?</comment>' . PHP_EOL . 'If you want to, just Enter');
|
|
||||||
if (!$ask) {
|
|
||||||
$output->writeln('<comment>User canceled.</comment>');
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
@unlink($phar_path);
|
|
||||||
}
|
|
||||||
$phar = new \Phar($phar_path);
|
|
||||||
$phar->startBuffering();
|
|
||||||
|
|
||||||
$all = DataProvider::scanDirFiles($path, true, true);
|
|
||||||
|
|
||||||
$all = array_filter($all, function ($x) {
|
|
||||||
$dirs = preg_match('/(^(config|src|vendor)\\/|^(composer\\.json|README\\.md|source\\.json|LICENSE|README-en\\.md)$)/', $x);
|
|
||||||
return !($dirs !== 1);
|
|
||||||
});
|
|
||||||
sort($all);
|
|
||||||
$map = [];
|
|
||||||
foreach ($all as $v) {
|
|
||||||
$map[$v] = $path . '/' . $v;
|
|
||||||
}
|
|
||||||
|
|
||||||
$output->writeln('<info>Start packing files...</info>');
|
|
||||||
try {
|
|
||||||
foreach ($this->progress($output)->iterate($map) as $file => $origin_file) {
|
|
||||||
$phar->addFromString($file, php_strip_whitespace($origin_file));
|
|
||||||
}
|
|
||||||
// $phar->buildFromIterator(new SeekableArrayIterator($map, new ProgressBar($output)));
|
|
||||||
$phar->addFromString(
|
|
||||||
'.phar-entry.php',
|
|
||||||
str_replace(
|
|
||||||
'/../vendor/autoload.php',
|
|
||||||
'/vendor/autoload.php',
|
|
||||||
file_get_contents(ROOT_DIR . '/bin/spc')
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$stub = '.phar-entry.php';
|
|
||||||
$phar->setStub($phar->createDefaultStub($stub));
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
$output->writeln($e);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
$phar->addFromString('.prod', 'true');
|
|
||||||
$phar->stopBuffering();
|
|
||||||
$output->writeln(PHP_EOL . 'Done! Phar file is generated at "' . $phar_path . '".');
|
|
||||||
if (file_exists(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx')) {
|
|
||||||
$output->writeln('Detected you have already compiled micro binary, I will make executable now for you!');
|
|
||||||
file_put_contents(
|
|
||||||
pathinfo($phar_path, PATHINFO_DIRNAME) . '/spc',
|
|
||||||
file_get_contents(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx') .
|
|
||||||
file_get_contents($phar_path)
|
|
||||||
);
|
|
||||||
chmod(pathinfo($phar_path, PATHINFO_DIRNAME) . '/spc', 0755);
|
|
||||||
$output->writeln('<info>Binary Executable: ' . pathinfo($phar_path, PATHINFO_DIRNAME) . '/spc</info>');
|
|
||||||
}
|
|
||||||
chmod($phar_path, 0755);
|
|
||||||
$output->writeln('<info>Phar Executable: ' . $phar_path . '</info>');
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function progress(OutputInterface $output, int $max = 0): ProgressBar
|
|
||||||
{
|
|
||||||
$progress = new ProgressBar($output, $max);
|
|
||||||
$progress->setBarCharacter('<fg=green>⚬</>');
|
|
||||||
$progress->setEmptyBarCharacter('<fg=red>⚬</>');
|
|
||||||
$progress->setProgressCharacter('<fg=green>➤</>');
|
|
||||||
$progress->setFormat(
|
|
||||||
"%current%/%max% [%bar%] %percent:3s%%\n🪅 %estimated:-20s% %memory:20s%" . PHP_EOL
|
|
||||||
);
|
|
||||||
return $progress;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\command;
|
|
||||||
|
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改 config 后对其 kv 进行排序的操作
|
|
||||||
*/
|
|
||||||
class DumpLicenseCommand extends BaseCommand
|
|
||||||
{
|
|
||||||
protected static $defaultName = 'dump-license';
|
|
||||||
|
|
||||||
public function configure()
|
|
||||||
{
|
|
||||||
$this->setDescription('Dump licenses for required libraries');
|
|
||||||
$this->addArgument('config-name', InputArgument::REQUIRED, 'Your config to be sorted, you can sort "lib", "source" and "ext".');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute(InputInterface $input, OutputInterface $output): int
|
|
||||||
{
|
|
||||||
$output->writeln('<info>not implemented</info>');
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,238 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\command;
|
|
||||||
|
|
||||||
use SPC\exception\DownloaderException;
|
|
||||||
use SPC\exception\ExceptionHandler;
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\InvalidArgumentException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\store\Config;
|
|
||||||
use SPC\store\Downloader;
|
|
||||||
use SPC\util\Patcher;
|
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
|
|
||||||
/** @noinspection PhpUnused */
|
|
||||||
class FetchSourceCommand extends BaseCommand
|
|
||||||
{
|
|
||||||
protected static $defaultName = 'fetch';
|
|
||||||
|
|
||||||
protected string $php_major_ver;
|
|
||||||
|
|
||||||
protected InputInterface $input;
|
|
||||||
|
|
||||||
public function configure()
|
|
||||||
{
|
|
||||||
$this->setDescription('Fetch required sources');
|
|
||||||
$this->addArgument('extensions', InputArgument::REQUIRED, 'The extensions will be compiled, comma separated');
|
|
||||||
$this->addArgument('libraries', InputArgument::REQUIRED, 'The libraries will be compiled, comma separated');
|
|
||||||
$this->addOption('hash', null, null, 'Hash only');
|
|
||||||
$this->addOption('shallow-clone', null, null, 'Clone shallow');
|
|
||||||
$this->addOption('with-openssl11', null, null, 'Use openssl 1.1');
|
|
||||||
$this->addOption('with-php', null, InputOption::VALUE_REQUIRED, 'version in major.minor format like 8.1', '8.1');
|
|
||||||
$this->addOption('clean', null, null, 'Clean old download cache and source before fetch');
|
|
||||||
$this->addOption('all', 'A', null, 'Fetch all sources that static-php-cli needed');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function initialize(InputInterface $input, OutputInterface $output)
|
|
||||||
{
|
|
||||||
// --all 等于 "" "",也就是所有东西都要下载
|
|
||||||
if ($input->getOption('all')) {
|
|
||||||
$input->setArgument('extensions', '');
|
|
||||||
$input->setArgument('libraries', '');
|
|
||||||
}
|
|
||||||
parent::initialize($input, $output);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute(InputInterface $input, OutputInterface $output): int
|
|
||||||
{
|
|
||||||
$this->input = $input;
|
|
||||||
try {
|
|
||||||
// 匹配版本
|
|
||||||
$ver = $this->php_major_ver = $input->getOption('with-php') ?? '8.1';
|
|
||||||
preg_match('/^\d+\.\d+$/', $ver, $matches);
|
|
||||||
if (!$matches) {
|
|
||||||
logger()->error("bad version arg: {$ver}, x.y required!");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除旧资源
|
|
||||||
if ($input->getOption('clean')) {
|
|
||||||
logger()->warning('You are doing some operations that not recoverable: removing directories below');
|
|
||||||
logger()->warning(SOURCE_PATH);
|
|
||||||
logger()->warning(DOWNLOAD_PATH);
|
|
||||||
logger()->warning('I will remove these dir after you press [Enter] !');
|
|
||||||
echo 'Confirm operation? [Yes] ';
|
|
||||||
$r = strtolower(trim(fgets(STDIN)));
|
|
||||||
if ($r !== 'yes' && $r !== '') {
|
|
||||||
logger()->notice('Operation canceled.');
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (PHP_OS_FAMILY === 'Windows') {
|
|
||||||
f_passthru('rmdir /s /q ' . SOURCE_PATH);
|
|
||||||
f_passthru('rmdir /s /q ' . DOWNLOAD_PATH);
|
|
||||||
} else {
|
|
||||||
f_passthru('rm -rf ' . SOURCE_PATH);
|
|
||||||
f_passthru('rm -rf ' . DOWNLOAD_PATH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用浅克隆可以减少调用 git 命令下载资源时的存储空间占用
|
|
||||||
if ($input->getOption('shallow-clone')) {
|
|
||||||
define('GIT_SHALLOW_CLONE', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 读取源配置,随便读一个source,用于缓存 source 配置
|
|
||||||
Config::getSource('openssl');
|
|
||||||
|
|
||||||
// 是否启用openssl11
|
|
||||||
if ($input->getOption('with-openssl11')) {
|
|
||||||
logger()->debug('Using openssl 1.1');
|
|
||||||
// 手动修改配置
|
|
||||||
Config::$source['openssl']['regex'] = '/href="(?<file>openssl-(?<version>1.[^"]+)\.tar\.gz)\"/';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 默认预选 phpmicro
|
|
||||||
$chosen_sources = ['micro'];
|
|
||||||
|
|
||||||
// 从参数中获取要编译的 libraries,并转换为数组
|
|
||||||
$libraries = array_map('trim', array_filter(explode(',', $input->getArgument('libraries'))));
|
|
||||||
if ($libraries) {
|
|
||||||
foreach ($libraries as $lib) {
|
|
||||||
// 从 lib 的 config 中找到对应 source 资源名称,组成一个 lib 的 source 列表
|
|
||||||
$src_name = Config::getLib($lib, 'source');
|
|
||||||
$chosen_sources[] = $src_name;
|
|
||||||
}
|
|
||||||
} else { // 如果传入了空串,那么代表 fetch 所有包
|
|
||||||
$chosen_sources = [...$chosen_sources, ...array_map(fn ($x) => $x['source'], array_values(Config::getLibs()))];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从参数中获取要编译的 extensions,并转换为数组
|
|
||||||
$extensions = array_map('trim', array_filter(explode(',', $input->getArgument('extensions'))));
|
|
||||||
if ($extensions) {
|
|
||||||
foreach ($extensions as $lib) {
|
|
||||||
if (Config::getExt($lib, 'type') !== 'builtin') {
|
|
||||||
$src_name = Config::getExt($lib, 'source');
|
|
||||||
$chosen_sources[] = $src_name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
foreach (Config::getExts() as $ext) {
|
|
||||||
if ($ext['type'] !== 'builtin') {
|
|
||||||
$chosen_sources[] = $ext['source'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$chosen_sources = array_unique($chosen_sources);
|
|
||||||
|
|
||||||
// 是否只hash,不下载资源
|
|
||||||
if ($input->getOption('hash')) {
|
|
||||||
$hash = $this->doHash($chosen_sources);
|
|
||||||
$output->writeln($hash);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建目录
|
|
||||||
f_mkdir(SOURCE_PATH);
|
|
||||||
f_mkdir(DOWNLOAD_PATH);
|
|
||||||
|
|
||||||
// 下载 PHP
|
|
||||||
logger()->info('Fetching PHP source');
|
|
||||||
Downloader::fetchSource('php-src', Downloader::getLatestPHPInfo($ver));
|
|
||||||
|
|
||||||
// 下载别的依赖资源
|
|
||||||
$cnt = count($chosen_sources);
|
|
||||||
$ni = 0;
|
|
||||||
foreach ($chosen_sources as $name) {
|
|
||||||
++$ni;
|
|
||||||
logger()->info("Fetching source {$name} [{$ni}/{$cnt}]");
|
|
||||||
Downloader::fetchSource($name, Config::getSource($name));
|
|
||||||
}
|
|
||||||
|
|
||||||
// patch 每份资源只需一次,如果已经下载好的资源已经patch了,就标记一下不patch了
|
|
||||||
if (!file_exists(SOURCE_PATH . '/.patched')) {
|
|
||||||
$this->doPatch();
|
|
||||||
} else {
|
|
||||||
logger()->notice('sources already patched');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打印拉取资源用时
|
|
||||||
$time = round(microtime(true) - START_TIME, 3);
|
|
||||||
logger()->info('Fetch complete, used ' . $time . ' s !');
|
|
||||||
return 0;
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
// 不开 debug 模式就不要再显示复杂的调试栈信息了
|
|
||||||
if ($input->getOption('debug')) {
|
|
||||||
ExceptionHandler::getInstance()->handle($e);
|
|
||||||
} else {
|
|
||||||
logger()->emergency($e->getMessage() . ', previous message: ' . $e->getPrevious()->getMessage());
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 计算资源名称列表的 Hash
|
|
||||||
*
|
|
||||||
* @param array $chosen_sources 要计算 hash 的资源名称列表
|
|
||||||
* @throws InvalidArgumentException
|
|
||||||
* @throws DownloaderException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
private function doHash(array $chosen_sources): string
|
|
||||||
{
|
|
||||||
$files = [];
|
|
||||||
foreach ($chosen_sources as $name) {
|
|
||||||
$source = Config::getSource($name);
|
|
||||||
$filename = match ($source['type']) {
|
|
||||||
'ghtar' => Downloader::getLatestGithubTarball($name, $source)[1],
|
|
||||||
'ghtagtar' => Downloader::getLatestGithubTarball($name, $source, 'tags')[1],
|
|
||||||
'ghrel' => Downloader::getLatestGithubRelease($name, $source)[1],
|
|
||||||
'filelist' => Downloader::getFromFileList($name, $source)[1],
|
|
||||||
'url' => $source['filename'] ?? basename($source['url']),
|
|
||||||
'git' => null,
|
|
||||||
default => throw new InvalidArgumentException('unknown source type: ' . $source['type']),
|
|
||||||
};
|
|
||||||
if ($filename !== null) {
|
|
||||||
logger()->info("found {$name} source: {$filename}");
|
|
||||||
$files[] = $filename;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hash('sha256', implode('|', $files));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 在拉回资源后,需要对一些文件做一些补丁 patch
|
|
||||||
*
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
private function doPatch(): void
|
|
||||||
{
|
|
||||||
// swow 需要软链接内部的文件夹才能正常编译
|
|
||||||
if (!file_exists(SOURCE_PATH . '/php-src/ext/swow')) {
|
|
||||||
Patcher::patchSwow();
|
|
||||||
}
|
|
||||||
// patch 一些 PHP 的资源,以便编译
|
|
||||||
Patcher::patchPHPDepFiles();
|
|
||||||
|
|
||||||
// openssl 3 需要 patch 额外的东西
|
|
||||||
if (!$this->input->getOption('with-openssl11') && $this->php_major_ver === '8.0') {
|
|
||||||
Patcher::patchOpenssl3();
|
|
||||||
}
|
|
||||||
|
|
||||||
// openssl1.1.1q 在 MacOS 上直接编译会报错,patch 一下
|
|
||||||
// @see: https://github.com/openssl/openssl/issues/18720
|
|
||||||
if ($this->input->getOption('with-openssl11') && file_exists(SOURCE_PATH . '/openssl/test/v3ext.c') && PHP_OS_FAMILY === 'Darwin') {
|
|
||||||
Patcher::patchDarwinOpenssl11();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 标记 patch 完成,避免重复 patch
|
|
||||||
file_put_contents(SOURCE_PATH . '/.patched', '');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\command;
|
|
||||||
|
|
||||||
use SPC\builder\traits\NoMotdTrait;
|
|
||||||
use SPC\store\Config;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
|
|
||||||
class ListExtCommand extends BaseCommand
|
|
||||||
{
|
|
||||||
use NoMotdTrait;
|
|
||||||
|
|
||||||
protected static $defaultName = 'list-ext';
|
|
||||||
|
|
||||||
public function configure()
|
|
||||||
{
|
|
||||||
$this->setDescription('List supported extensions');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute(InputInterface $input, OutputInterface $output)
|
|
||||||
{
|
|
||||||
foreach (Config::getExts() as $ext => $meta) {
|
|
||||||
echo $ext . PHP_EOL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\command;
|
|
||||||
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\ValidationException;
|
|
||||||
use SPC\store\FileSystem;
|
|
||||||
use SPC\util\ConfigValidator;
|
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改 config 后对其 kv 进行排序的操作
|
|
||||||
*/
|
|
||||||
class SortConfigCommand extends BaseCommand
|
|
||||||
{
|
|
||||||
protected static $defaultName = 'sort-config';
|
|
||||||
|
|
||||||
public function configure()
|
|
||||||
{
|
|
||||||
$this->setDescription('After config edited, sort it by alphabet');
|
|
||||||
$this->addArgument('config-name', InputArgument::REQUIRED, 'Your config to be sorted, you can sort "lib", "source" and "ext".');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws ValidationException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public function execute(InputInterface $input, OutputInterface $output): int
|
|
||||||
{
|
|
||||||
switch ($name = $input->getArgument('config-name')) {
|
|
||||||
case 'lib':
|
|
||||||
$file = json_decode(FileSystem::readFile(ROOT_DIR . '/config/lib.json'), true);
|
|
||||||
ConfigValidator::validateLibs($file);
|
|
||||||
ksort($file);
|
|
||||||
file_put_contents(ROOT_DIR . '/config/lib.json', json_encode($file, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
|
||||||
break;
|
|
||||||
case 'source':
|
|
||||||
$file = json_decode(FileSystem::readFile(ROOT_DIR . '/config/source.json'), true);
|
|
||||||
ConfigValidator::validateSource($file);
|
|
||||||
ksort($file);
|
|
||||||
file_put_contents(ROOT_DIR . '/config/source.json', json_encode($file, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
|
||||||
break;
|
|
||||||
case 'ext':
|
|
||||||
$file = json_decode(FileSystem::readFile(ROOT_DIR . '/config/ext.json'), true);
|
|
||||||
ConfigValidator::validateExts($file);
|
|
||||||
ksort($file);
|
|
||||||
file_put_contents(ROOT_DIR . '/config/ext.json', json_encode($file, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$output->writeln("<error>invalid config name: {$name}</error>");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
$output->writeln('<info>sort success</info>');
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\exception;
|
|
||||||
|
|
||||||
class DownloaderException extends \Exception
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\exception;
|
|
||||||
|
|
||||||
class ExceptionHandler
|
|
||||||
{
|
|
||||||
protected $whoops;
|
|
||||||
|
|
||||||
private static $obj;
|
|
||||||
|
|
||||||
private function __construct()
|
|
||||||
{
|
|
||||||
$whoops_class = 'Whoops\Run';
|
|
||||||
$collision_class = 'NunoMaduro\Collision\Handler';
|
|
||||||
if (class_exists($collision_class) && class_exists($whoops_class)) {
|
|
||||||
/* @phpstan-ignore-next-line */
|
|
||||||
$this->whoops = new $whoops_class();
|
|
||||||
$this->whoops->allowQuit(false);
|
|
||||||
$this->whoops->writeToOutput(false);
|
|
||||||
$this->whoops->pushHandler(new $collision_class());
|
|
||||||
$this->whoops->register();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getInstance(): ExceptionHandler
|
|
||||||
{
|
|
||||||
if (self::$obj === null) {
|
|
||||||
self::$obj = new self();
|
|
||||||
}
|
|
||||||
return self::$obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getWhoops()
|
|
||||||
{
|
|
||||||
return $this->whoops;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理异常
|
|
||||||
*/
|
|
||||||
public function handle(\Throwable $e): void
|
|
||||||
{
|
|
||||||
if (is_null($this->whoops)) {
|
|
||||||
logger()->error('Uncaught ' . get_class($e) . ': ' . $e->getMessage() . ' at ' . $e->getFile() . '(' . $e->getLine() . ')');
|
|
||||||
logger()->error($e->getTraceAsString());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->whoops->handleException($e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\exception;
|
|
||||||
|
|
||||||
class FileSystemException extends \Exception
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\exception;
|
|
||||||
|
|
||||||
class InvalidArgumentException extends \Exception
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\exception;
|
|
||||||
|
|
||||||
class RuntimeException extends \Exception
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\exception;
|
|
||||||
|
|
||||||
class ValidationException extends \Exception
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\store;
|
|
||||||
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 一个读取 config 配置的操作类
|
|
||||||
*/
|
|
||||||
class Config
|
|
||||||
{
|
|
||||||
public static ?array $source = null;
|
|
||||||
|
|
||||||
public static ?array $lib = null;
|
|
||||||
|
|
||||||
public static ?array $ext = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从配置文件读取一个资源(source)的元信息
|
|
||||||
*
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public static function getSource(string $name): ?array
|
|
||||||
{
|
|
||||||
if (self::$source === null) {
|
|
||||||
self::$source = FileSystem::loadConfigArray('source');
|
|
||||||
}
|
|
||||||
return self::$source[$name] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据不同的操作系统分别选择不同的 lib 库依赖项
|
|
||||||
* 如果 key 为 null,那么直接返回整个 meta。
|
|
||||||
* 如果 key 不为 null,则可以使用的 key 有 static-libs、headers、lib-depends、lib-suggests。
|
|
||||||
* 对于 macOS 平台,支持 frameworks。
|
|
||||||
*
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function getLib(string $name, ?string $key = null, mixed $default = null)
|
|
||||||
{
|
|
||||||
if (self::$lib === null) {
|
|
||||||
self::$lib = FileSystem::loadConfigArray('lib');
|
|
||||||
}
|
|
||||||
if (!isset(self::$lib[$name])) {
|
|
||||||
throw new RuntimeException('lib [' . $name . '] is not supported yet for get');
|
|
||||||
}
|
|
||||||
$supported_sys_based = ['static-libs', 'headers', 'lib-depends', 'lib-suggests', 'frameworks'];
|
|
||||||
if ($key !== null && in_array($key, $supported_sys_based)) {
|
|
||||||
$m_key = match (PHP_OS_FAMILY) {
|
|
||||||
'Windows' => ['-windows', '-win', ''],
|
|
||||||
'Darwin' => ['-macos', '-unix', ''],
|
|
||||||
'Linux' => ['-linux', '-unix', ''],
|
|
||||||
default => throw new RuntimeException('OS ' . PHP_OS_FAMILY . ' is not supported'),
|
|
||||||
};
|
|
||||||
foreach ($m_key as $v) {
|
|
||||||
if (isset(self::$lib[$name][$key . $v])) {
|
|
||||||
return self::$lib[$name][$key . $v];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $default;
|
|
||||||
}
|
|
||||||
if ($key !== null) {
|
|
||||||
return self::$lib[$name][$key] ?? $default;
|
|
||||||
}
|
|
||||||
return self::$lib[$name];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public static function getLibs(): array
|
|
||||||
{
|
|
||||||
if (self::$lib === null) {
|
|
||||||
self::$lib = FileSystem::loadConfigArray('lib');
|
|
||||||
}
|
|
||||||
return self::$lib;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function getExt(string $name, ?string $key = null, mixed $default = null)
|
|
||||||
{
|
|
||||||
if (self::$ext === null) {
|
|
||||||
self::$ext = FileSystem::loadConfigArray('ext');
|
|
||||||
}
|
|
||||||
if (!isset(self::$ext[$name])) {
|
|
||||||
throw new RuntimeException('ext [' . $name . '] is not supported yet for get');
|
|
||||||
}
|
|
||||||
$supported_sys_based = ['lib-depends', 'lib-suggests', 'ext-depends', 'ext-suggests', 'arg-type'];
|
|
||||||
if ($key !== null && in_array($key, $supported_sys_based)) {
|
|
||||||
$m_key = match (PHP_OS_FAMILY) {
|
|
||||||
'Windows' => ['-windows', '-win', ''],
|
|
||||||
'Darwin' => ['-macos', '-unix', ''],
|
|
||||||
'Linux' => ['-linux', '-unix', ''],
|
|
||||||
default => throw new RuntimeException('OS ' . PHP_OS_FAMILY . ' is not supported'),
|
|
||||||
};
|
|
||||||
foreach ($m_key as $v) {
|
|
||||||
if (isset(self::$ext[$name][$key . $v])) {
|
|
||||||
return self::$ext[$name][$key . $v];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $default;
|
|
||||||
}
|
|
||||||
if ($key !== null) {
|
|
||||||
return self::$ext[$name][$key] ?? $default;
|
|
||||||
}
|
|
||||||
return self::$ext[$name];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public static function getExts(): array
|
|
||||||
{
|
|
||||||
if (self::$ext === null) {
|
|
||||||
self::$ext = FileSystem::loadConfigArray('ext');
|
|
||||||
}
|
|
||||||
return self::$ext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\store;
|
|
||||||
|
|
||||||
class CurlHook
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 执行 GitHub Token 的 Curl 头添加
|
|
||||||
*
|
|
||||||
* @param string $method 修改的 method
|
|
||||||
* @param string $url 修改的链接
|
|
||||||
* @param array $headers 修改的 headers
|
|
||||||
*/
|
|
||||||
public static function setupGithubToken(string &$method, string &$url, array &$headers): void
|
|
||||||
{
|
|
||||||
if (!getenv('GITHUB_TOKEN')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (getenv('GITHUB_USER')) {
|
|
||||||
$auth = base64_encode(getenv('GITHUB_USER') . ':' . getenv('GITHUB_TOKEN'));
|
|
||||||
$headers[] = "Authorization: Basic {$auth}";
|
|
||||||
logger()->info("using basic github token for {$method} {$url}");
|
|
||||||
} else {
|
|
||||||
$auth = getenv('GITHUB_TOKEN');
|
|
||||||
$headers[] = "Authorization: Bearer {$auth}";
|
|
||||||
logger()->info("using bearer github token for {$method} {$url}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,371 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\store;
|
|
||||||
|
|
||||||
use JetBrains\PhpStorm\ArrayShape;
|
|
||||||
use SPC\exception\DownloaderException;
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 资源下载器
|
|
||||||
*/
|
|
||||||
class Downloader
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 获取 BitBucket 仓库的最新 Tag
|
|
||||||
*
|
|
||||||
* @param string $name 资源名称
|
|
||||||
* @param array $source 资源的元信息,包含字段 repo
|
|
||||||
* @return array<int, string> 返回下载 url 链接和文件名
|
|
||||||
* @throws DownloaderException
|
|
||||||
*/
|
|
||||||
public static function getLatestBitbucketTag(string $name, array $source): array
|
|
||||||
{
|
|
||||||
logger()->debug("finding {$name} source from bitbucket tag");
|
|
||||||
$data = json_decode(self::curlExec(
|
|
||||||
url: "https://api.bitbucket.org/2.0/repositories/{$source['repo']}/refs/tags"
|
|
||||||
), true);
|
|
||||||
$ver = $data['values'][0]['name'];
|
|
||||||
if (!$ver) {
|
|
||||||
throw new DownloaderException("failed to find {$name} bitbucket source");
|
|
||||||
}
|
|
||||||
$url = "https://bitbucket.org/{$source['repo']}/get/{$ver}.tar.gz";
|
|
||||||
$headers = self::curlExec(
|
|
||||||
url: $url,
|
|
||||||
method: 'HEAD'
|
|
||||||
);
|
|
||||||
preg_match('/^content-disposition:\s+attachment;\s*filename=("?)(?<filename>.+\.tar\.gz)\1/im', $headers, $matches);
|
|
||||||
if ($matches) {
|
|
||||||
$filename = $matches['filename'];
|
|
||||||
} else {
|
|
||||||
$filename = "{$name}-{$data['tag_name']}.tar.gz";
|
|
||||||
}
|
|
||||||
|
|
||||||
return [$url, $filename];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取 GitHub 最新的打包地址和文件名
|
|
||||||
*
|
|
||||||
* @param string $name 包名称
|
|
||||||
* @param array $source 源信息
|
|
||||||
* @throws DownloaderException
|
|
||||||
*/
|
|
||||||
public static function getLatestGithubTarball(string $name, array $source, string $type = 'releases'): array
|
|
||||||
{
|
|
||||||
logger()->debug("finding {$name} source from github {$type} tarball");
|
|
||||||
$data = json_decode(self::curlExec(
|
|
||||||
url: "https://api.github.com/repos/{$source['repo']}/{$type}",
|
|
||||||
hooks: [[CurlHook::class, 'setupGithubToken']]
|
|
||||||
), true);
|
|
||||||
$url = $data[0]['tarball_url'];
|
|
||||||
if (!$url) {
|
|
||||||
throw new DownloaderException("failed to find {$name} source");
|
|
||||||
}
|
|
||||||
$headers = self::curlExec(
|
|
||||||
url: $url,
|
|
||||||
method: 'HEAD',
|
|
||||||
hooks: [[CurlHook::class, 'setupGithubToken']],
|
|
||||||
);
|
|
||||||
preg_match('/^content-disposition:\s+attachment;\s*filename=("?)(?<filename>.+\.tar\.gz)\1/im', $headers, $matches);
|
|
||||||
if ($matches) {
|
|
||||||
$filename = $matches['filename'];
|
|
||||||
} else {
|
|
||||||
$filename = "{$name}-" . ($type === 'releases' ? $data['tag_name'] : $data['name']) . '.tar.gz';
|
|
||||||
}
|
|
||||||
|
|
||||||
return [$url, $filename];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取 GitHub 最新的 Release 下载信息
|
|
||||||
*
|
|
||||||
* @param string $name 资源名
|
|
||||||
* @param array $source 资源的元信息,包含字段 repo、match
|
|
||||||
* @throws DownloaderException
|
|
||||||
*/
|
|
||||||
public static function getLatestGithubRelease(string $name, array $source): array
|
|
||||||
{
|
|
||||||
logger()->debug("finding {$name} source from github releases assests");
|
|
||||||
$data = json_decode(self::curlExec(
|
|
||||||
url: "https://api.github.com/repos/{$source['repo']}/releases",
|
|
||||||
hooks: [[CurlHook::class, 'setupGithubToken']],
|
|
||||||
), true);
|
|
||||||
$url = null;
|
|
||||||
foreach ($data[0]['assets'] as $asset) {
|
|
||||||
if (preg_match('|' . $source['match'] . '|', $asset['name'])) {
|
|
||||||
$url = $asset['browser_download_url'];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!$url) {
|
|
||||||
throw new DownloaderException("failed to find {$name} source");
|
|
||||||
}
|
|
||||||
$filename = basename($url);
|
|
||||||
|
|
||||||
return [$url, $filename];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文件列表的资源链接和名称
|
|
||||||
*
|
|
||||||
* @param string $name 资源名称
|
|
||||||
* @param array $source 资源元信息,包含 url、regex
|
|
||||||
* @throws DownloaderException
|
|
||||||
*/
|
|
||||||
public static function getFromFileList(string $name, array $source): array
|
|
||||||
{
|
|
||||||
logger()->debug("finding {$name} source from file list");
|
|
||||||
$page = self::curlExec($source['url']);
|
|
||||||
preg_match_all($source['regex'], $page, $matches);
|
|
||||||
if (!$matches) {
|
|
||||||
throw new DownloaderException("Failed to get {$name} version");
|
|
||||||
}
|
|
||||||
$versions = [];
|
|
||||||
foreach ($matches['version'] as $i => $version) {
|
|
||||||
$lowerVersion = strtolower($version);
|
|
||||||
foreach ([
|
|
||||||
'alpha',
|
|
||||||
'beta',
|
|
||||||
'rc',
|
|
||||||
'pre',
|
|
||||||
'nightly',
|
|
||||||
'snapshot',
|
|
||||||
'dev',
|
|
||||||
] as $betaVersion) {
|
|
||||||
if (str_contains($lowerVersion, $betaVersion)) {
|
|
||||||
continue 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$versions[$version] = $matches['file'][$i];
|
|
||||||
}
|
|
||||||
uksort($versions, 'version_compare');
|
|
||||||
|
|
||||||
return [$source['url'] . end($versions), end($versions)];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过链接下载资源到本地并解压
|
|
||||||
*
|
|
||||||
* @param string $name 资源名称
|
|
||||||
* @param string $url 下载链接
|
|
||||||
* @param string $filename 下载到下载目录的目标文件名称,例如 xz.tar.gz
|
|
||||||
* @param null|string $path 如果指定了此参数,则会移动该资源目录到目标目录
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws DownloaderException
|
|
||||||
*/
|
|
||||||
public static function downloadUrl(string $name, string $url, string $filename, ?string $path = null): void
|
|
||||||
{
|
|
||||||
if (!file_exists(DOWNLOAD_PATH . "/{$filename}")) {
|
|
||||||
logger()->debug("downloading {$url}");
|
|
||||||
self::curlDown(url: $url, path: DOWNLOAD_PATH . "/{$filename}");
|
|
||||||
} else {
|
|
||||||
logger()->notice("{$filename} already exists");
|
|
||||||
}
|
|
||||||
FileSystem::extractSource($name, DOWNLOAD_PATH . "/{$filename}");
|
|
||||||
if ($path) {
|
|
||||||
$path = FileSystem::convertPath(SOURCE_PATH . "/{$path}");
|
|
||||||
$src_path = FileSystem::convertPath(SOURCE_PATH . "/{$name}");
|
|
||||||
switch (PHP_OS_FAMILY) {
|
|
||||||
case 'Windows':
|
|
||||||
f_passthru('move "' . $src_path . '" "' . $path . '"');
|
|
||||||
break;
|
|
||||||
case 'Linux':
|
|
||||||
case 'Darwin':
|
|
||||||
f_passthru('mv "' . $src_path . '" "' . $path . '"');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function downloadGit(string $name, string $url, string $branch, ?string $path = null): void
|
|
||||||
{
|
|
||||||
if ($path !== null) {
|
|
||||||
$path = SOURCE_PATH . "/{$path}";
|
|
||||||
} else {
|
|
||||||
$path = DOWNLOAD_PATH . "/{$name}";
|
|
||||||
}
|
|
||||||
$download_path = DOWNLOAD_PATH . "/{$name}";
|
|
||||||
if (file_exists($download_path)) {
|
|
||||||
logger()->notice("{$name} git source already fetched");
|
|
||||||
} else {
|
|
||||||
logger()->debug("cloning {$name} source");
|
|
||||||
$check = !defined('DEBUG_MODE') ? ' -q' : '';
|
|
||||||
f_passthru(
|
|
||||||
'git clone' . $check .
|
|
||||||
' --config core.autocrlf=false ' .
|
|
||||||
"--branch \"{$branch}\" " . (defined('GIT_SHALLOW_CLONE') ? '--depth 1 --single-branch' : '') . " --recursive \"{$url}\" \"{$download_path}\""
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// 复制目录过去
|
|
||||||
if ($path !== $download_path) {
|
|
||||||
$dst_path = FileSystem::convertPath($path);
|
|
||||||
$src_path = FileSystem::convertPath($download_path);
|
|
||||||
switch (PHP_OS_FAMILY) {
|
|
||||||
case 'Windows':
|
|
||||||
f_passthru('xcopy "' . $src_path . '" "' . $dst_path . '" /s/e/v/y/i');
|
|
||||||
break;
|
|
||||||
case 'Linux':
|
|
||||||
case 'Darwin':
|
|
||||||
f_passthru('cp -r "' . $src_path . '" "' . $dst_path . '"');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 拉取资源
|
|
||||||
*
|
|
||||||
* @param string $name 资源名称
|
|
||||||
* @param array $source 资源参数,包含 type、path、rev、url、filename、regex、license
|
|
||||||
* @throws DownloaderException
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public static function fetchSource(string $name, array $source): void
|
|
||||||
{
|
|
||||||
// 如果是 git 类型,且没有设置 path,那我就需要指定一下 path
|
|
||||||
if ($source['type'] === 'git' && !isset($source['path'])) {
|
|
||||||
$source['path'] = $name;
|
|
||||||
}
|
|
||||||
// 避免重复 fetch
|
|
||||||
if (!isset($source['path']) && is_dir(FileSystem::convertPath(DOWNLOAD_PATH . "/{$name}")) || isset($source['path']) && is_dir(FileSystem::convertPath(SOURCE_PATH . "/{$source['path']}"))) {
|
|
||||||
logger()->notice("{$name} source already extracted");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
switch ($source['type']) {
|
|
||||||
case 'bitbuckettag': // 从 BitBucket 的 Tag 拉取
|
|
||||||
[$url, $filename] = self::getLatestBitbucketTag($name, $source);
|
|
||||||
self::downloadUrl($name, $url, $filename, $source['path'] ?? null);
|
|
||||||
break;
|
|
||||||
case 'ghtar': // 从 GitHub 的 TarBall 拉取
|
|
||||||
[$url, $filename] = self::getLatestGithubTarball($name, $source);
|
|
||||||
self::downloadUrl($name, $url, $filename, $source['path'] ?? null);
|
|
||||||
break;
|
|
||||||
case 'ghtagtar': // 根据 GitHub 的 Tag 拉取相应版本的 Tar
|
|
||||||
[$url, $filename] = self::getLatestGithubTarball($name, $source, 'tags');
|
|
||||||
self::downloadUrl($name, $url, $filename, $source['path'] ?? null);
|
|
||||||
break;
|
|
||||||
case 'ghrel': // 通过 GitHub Release 来拉取
|
|
||||||
[$url, $filename] = self::getLatestGithubRelease($name, $source);
|
|
||||||
self::downloadUrl($name, $url, $filename, $source['path'] ?? null);
|
|
||||||
break;
|
|
||||||
case 'filelist': // 通过网站提供的 filelist 使用正则提取后拉取
|
|
||||||
[$url, $filename] = self::getFromFileList($name, $source);
|
|
||||||
self::downloadUrl($name, $url, $filename, $source['path'] ?? null);
|
|
||||||
break;
|
|
||||||
case 'url': // 通过直链拉取
|
|
||||||
$url = $source['url'];
|
|
||||||
$filename = $source['filename'] ?? basename($source['url']);
|
|
||||||
self::downloadUrl($name, $url, $filename, $source['path'] ?? null);
|
|
||||||
break;
|
|
||||||
case 'git': // 通过拉回 Git 仓库的形式拉取
|
|
||||||
self::downloadGit($name, $source['url'], $source['rev'], $source['path'] ?? null);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new DownloaderException('unknown source type: ' . $source['type']);
|
|
||||||
}
|
|
||||||
} catch (RuntimeException $e) {
|
|
||||||
// 因为某些时候通过命令行下载的文件在失败后不会删除,这里检测到文件存在需要手动删一下
|
|
||||||
if (isset($filename) && file_exists(DOWNLOAD_PATH . '/' . $filename)) {
|
|
||||||
logger()->warning('Deleting download file: ' . $filename);
|
|
||||||
unlink(DOWNLOAD_PATH . '/' . $filename);
|
|
||||||
}
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取 PHP x.y 的具体版本号,例如通过 8.1 来获取 8.1.10
|
|
||||||
*
|
|
||||||
* @throws DownloaderException
|
|
||||||
*/
|
|
||||||
#[ArrayShape(['type' => 'string', 'path' => 'string', 'rev' => 'string', 'url' => 'string'])]
|
|
||||||
public static function getLatestPHPInfo(string $major_version): array
|
|
||||||
{
|
|
||||||
// 查找最新的小版本号
|
|
||||||
$info = json_decode(self::curlExec(url: "https://www.php.net/releases/index.php?json&version={$major_version}"), true);
|
|
||||||
$version = $info['version'];
|
|
||||||
|
|
||||||
// 从官网直接下载
|
|
||||||
return [
|
|
||||||
'type' => 'url',
|
|
||||||
// 'url' => "https://www.php.net/distributions/php-{$version}.tar.gz",
|
|
||||||
'url' => "https://mirrors.zhamao.xin/php/php-{$version}.tar.gz",
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用 curl 命令拉取元信息
|
|
||||||
*
|
|
||||||
* @throws DownloaderException
|
|
||||||
*/
|
|
||||||
public static function curlExec(string $url, string $method = 'GET', array $headers = [], array $hooks = []): string
|
|
||||||
{
|
|
||||||
foreach ($hooks as $hook) {
|
|
||||||
$hook($method, $url, $headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
FileSystem::findCommandPath('curl');
|
|
||||||
|
|
||||||
$methodArg = match ($method) {
|
|
||||||
'GET' => '',
|
|
||||||
'HEAD' => '-I',
|
|
||||||
default => "-X \"{$method}\"",
|
|
||||||
};
|
|
||||||
$headerArg = implode(' ', array_map(fn ($v) => '"-H' . $v . '"', $headers));
|
|
||||||
|
|
||||||
$cmd = "curl -sfSL {$methodArg} {$headerArg} \"{$url}\"";
|
|
||||||
if (getenv('CACHE_API_EXEC') === 'yes') {
|
|
||||||
if (!file_exists(SOURCE_PATH . '/.curl_exec_cache')) {
|
|
||||||
$cache = [];
|
|
||||||
} else {
|
|
||||||
$cache = json_decode(file_get_contents(SOURCE_PATH . '/.curl_exec_cache'), true);
|
|
||||||
}
|
|
||||||
if (isset($cache[$cmd]) && $cache[$cmd]['expire'] >= time()) {
|
|
||||||
return $cache[$cmd]['cache'];
|
|
||||||
}
|
|
||||||
f_exec($cmd, $output, $ret);
|
|
||||||
if ($ret !== 0) {
|
|
||||||
throw new DownloaderException('failed http fetch');
|
|
||||||
}
|
|
||||||
$cache[$cmd]['cache'] = implode("\n", $output);
|
|
||||||
$cache[$cmd]['expire'] = time() + 3600;
|
|
||||||
file_put_contents(SOURCE_PATH . '/.curl_exec_cache', json_encode($cache));
|
|
||||||
return $cache[$cmd]['cache'];
|
|
||||||
}
|
|
||||||
f_exec($cmd, $output, $ret);
|
|
||||||
if ($ret !== 0) {
|
|
||||||
throw new DownloaderException('failed http fetch');
|
|
||||||
}
|
|
||||||
return implode("\n", $output);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用 curl 命令下载文件
|
|
||||||
*
|
|
||||||
* @throws DownloaderException
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function curlDown(string $url, string $path, string $method = 'GET', array $headers = [], array $hooks = []): void
|
|
||||||
{
|
|
||||||
foreach ($hooks as $hook) {
|
|
||||||
$hook($method, $url, $headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
$methodArg = match ($method) {
|
|
||||||
'GET' => '',
|
|
||||||
'HEAD' => '-I',
|
|
||||||
default => "-X \"{$method}\"",
|
|
||||||
};
|
|
||||||
$headerArg = implode(' ', array_map(fn ($v) => '"-H' . $v . '"', $headers));
|
|
||||||
$check = !defined('DEBUG_MODE') ? 's' : '#';
|
|
||||||
$cmd = "curl -{$check}fSL -o \"{$path}\" {$methodArg} {$headerArg} \"{$url}\"";
|
|
||||||
f_passthru($cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,388 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\store;
|
|
||||||
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator;
|
|
||||||
|
|
||||||
class FileSystem
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public static function loadConfigArray(string $config): array
|
|
||||||
{
|
|
||||||
$whitelist = ['ext', 'lib', 'source'];
|
|
||||||
if (!in_array($config, $whitelist)) {
|
|
||||||
throw new FileSystemException('Reading ' . $config . '.json is not allowed');
|
|
||||||
}
|
|
||||||
$tries = [
|
|
||||||
WORKING_DIR . '/config/' . $config . '.json',
|
|
||||||
ROOT_DIR . '/config/' . $config . '.json',
|
|
||||||
];
|
|
||||||
foreach ($tries as $try) {
|
|
||||||
if (file_exists($try)) {
|
|
||||||
$json = json_decode(self::readFile($try), true);
|
|
||||||
if (!is_array($json)) {
|
|
||||||
throw new FileSystemException('Reading ' . $try . ' failed');
|
|
||||||
}
|
|
||||||
return $json;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new FileSystemException('Reading ' . $config . '.json failed');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 读取文件,读不出来直接抛出异常
|
|
||||||
*
|
|
||||||
* @param string $filename 文件路径
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public static function readFile(string $filename): string
|
|
||||||
{
|
|
||||||
// logger()->debug('Reading file: ' . $filename);
|
|
||||||
$r = file_get_contents(self::convertPath($filename));
|
|
||||||
if ($r === false) {
|
|
||||||
throw new FileSystemException('Reading file ' . $filename . ' failed');
|
|
||||||
}
|
|
||||||
return $r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public static function replaceFile(string $filename, int $replace_type = REPLACE_FILE_STR, mixed $callback_or_search = null, mixed $to_replace = null): bool|int
|
|
||||||
{
|
|
||||||
logger()->debug('Replacing file with type[' . $replace_type . ']: ' . $filename);
|
|
||||||
$file = self::readFile($filename);
|
|
||||||
switch ($replace_type) {
|
|
||||||
case REPLACE_FILE_STR:
|
|
||||||
default:
|
|
||||||
$file = str_replace($callback_or_search, $to_replace, $file);
|
|
||||||
break;
|
|
||||||
case REPLACE_FILE_PREG:
|
|
||||||
$file = preg_replace($callback_or_search, $to_replace, $file);
|
|
||||||
break;
|
|
||||||
case REPLACE_FILE_USER:
|
|
||||||
$file = $callback_or_search($file);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return file_put_contents($filename, $file);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文件后缀
|
|
||||||
*
|
|
||||||
* @param string $fn 文件名
|
|
||||||
*/
|
|
||||||
public static function extname(string $fn): string
|
|
||||||
{
|
|
||||||
$parts = explode('.', basename($fn));
|
|
||||||
if (count($parts) < 2) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
return array_pop($parts);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 寻找命令的真实路径,效果类似 which
|
|
||||||
*
|
|
||||||
* @param string $name 命令名称
|
|
||||||
* @param array $paths 路径列表,如果为空则默认从 PATH 系统变量搜索
|
|
||||||
*/
|
|
||||||
public static function findCommandPath(string $name, array $paths = []): ?string
|
|
||||||
{
|
|
||||||
if (!$paths) {
|
|
||||||
$paths = explode(PATH_SEPARATOR, getenv('PATH'));
|
|
||||||
}
|
|
||||||
if (PHP_OS_FAMILY === 'Windows') {
|
|
||||||
foreach ($paths as $path) {
|
|
||||||
foreach (['.exe', '.bat', '.cmd'] as $suffix) {
|
|
||||||
if (file_exists($path . DIRECTORY_SEPARATOR . $name . $suffix)) {
|
|
||||||
return $path . DIRECTORY_SEPARATOR . $name . $suffix;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
foreach ($paths as $path) {
|
|
||||||
if (file_exists($path . DIRECTORY_SEPARATOR . $name)) {
|
|
||||||
return $path . DIRECTORY_SEPARATOR . $name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function copyDir(string $from, string $to): void
|
|
||||||
{
|
|
||||||
$iterator = new \RecursiveIteratorIterator(new RecursiveDirectoryIterator($from, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_FILEINFO), \RecursiveIteratorIterator::SELF_FIRST);
|
|
||||||
foreach ($iterator as $item) {
|
|
||||||
/**
|
|
||||||
* @var \SplFileInfo $item
|
|
||||||
*/
|
|
||||||
$target = $to . substr($item->getPathname(), strlen($from));
|
|
||||||
if ($item->isDir()) {
|
|
||||||
logger()->info("mkdir {$target}");
|
|
||||||
f_mkdir($target, recursive: true);
|
|
||||||
} else {
|
|
||||||
logger()->info("copying {$item} to {$target}");
|
|
||||||
@f_mkdir(dirname($target), recursive: true);
|
|
||||||
copy($item->getPathname(), $target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解压缩下载的资源包到 source 目录
|
|
||||||
*
|
|
||||||
* @param string $name 资源名
|
|
||||||
* @param string $filename 文件名
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function extractSource(string $name, string $filename): void
|
|
||||||
{
|
|
||||||
logger()->info("extracting {$name} source");
|
|
||||||
try {
|
|
||||||
if (PHP_OS_FAMILY !== 'Windows') {
|
|
||||||
if (f_mkdir(directory: SOURCE_PATH . "/{$name}", recursive: true) !== true) {
|
|
||||||
throw new FileSystemException('create ' . $name . 'source dir failed');
|
|
||||||
}
|
|
||||||
switch (self::extname($filename)) {
|
|
||||||
case 'xz':
|
|
||||||
case 'txz':
|
|
||||||
f_passthru("tar -xf {$filename} -C " . SOURCE_PATH . "/{$name} --strip-components 1");
|
|
||||||
// f_passthru("cat {$filename} | xz -d | tar -x -C " . SOURCE_PATH . "/{$name} --strip-components 1");
|
|
||||||
break;
|
|
||||||
case 'gz':
|
|
||||||
case 'tgz':
|
|
||||||
f_passthru("tar -xzf {$filename} -C " . SOURCE_PATH . "/{$name} --strip-components 1");
|
|
||||||
break;
|
|
||||||
case 'bz2':
|
|
||||||
f_passthru("tar -xjf {$filename} -C " . SOURCE_PATH . "/{$name} --strip-components 1");
|
|
||||||
break;
|
|
||||||
case 'zip':
|
|
||||||
f_passthru("unzip {$filename} -d " . SOURCE_PATH . "/{$name}");
|
|
||||||
break;
|
|
||||||
// case 'zstd':
|
|
||||||
// case 'zst':
|
|
||||||
// passthru('cat ' . $filename . ' | zstd -d | tar -x -C ".SOURCE_PATH . "/' . $name . ' --strip-components 1', $ret);
|
|
||||||
// break;
|
|
||||||
case 'tar':
|
|
||||||
f_passthru("tar -xf {$filename} -C " . SOURCE_PATH . "/{$name} --strip-components 1");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new FileSystemException('unknown archive format: ' . $filename);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// find 7z
|
|
||||||
$_7zExe = self::findCommandPath('7z', [
|
|
||||||
'C:\Program Files\7-Zip-Zstandard',
|
|
||||||
'C:\Program Files (x86)\7-Zip-Zstandard',
|
|
||||||
'C:\Program Files\7-Zip',
|
|
||||||
'C:\Program Files (x86)\7-Zip',
|
|
||||||
]);
|
|
||||||
if (!$_7zExe) {
|
|
||||||
throw new FileSystemException('windows needs 7z to unpack');
|
|
||||||
}
|
|
||||||
f_mkdir(SOURCE_PATH . "/{$name}", recursive: true);
|
|
||||||
switch (self::extname($filename)) {
|
|
||||||
case 'zstd':
|
|
||||||
case 'zst':
|
|
||||||
if (!str_contains($_7zExe, 'Zstandard')) {
|
|
||||||
throw new FileSystemException("zstd is not supported: {$filename}");
|
|
||||||
}
|
|
||||||
// no break
|
|
||||||
case 'xz':
|
|
||||||
case 'txz':
|
|
||||||
case 'gz':
|
|
||||||
case 'tgz':
|
|
||||||
case 'bz2':
|
|
||||||
f_passthru("\"{$_7zExe}\" x -so {$filename} | tar -f - -x -C " . SOURCE_PATH . "/{$name} --strip-components 1");
|
|
||||||
break;
|
|
||||||
case 'tar':
|
|
||||||
f_passthru("tar -xf {$filename} -C " . SOURCE_PATH . "/{$name} --strip-components 1");
|
|
||||||
break;
|
|
||||||
case 'zip':
|
|
||||||
f_passthru("\"{$_7zExe}\" x {$filename} -o" . SOURCE_PATH . "/{$name}");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new FileSystemException("unknown archive format: {$filename}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (RuntimeException $e) {
|
|
||||||
if (PHP_OS_FAMILY === 'Windows') {
|
|
||||||
f_passthru('rmdir /s /q ' . SOURCE_PATH . "/{$name}");
|
|
||||||
} else {
|
|
||||||
f_passthru('rm -r ' . SOURCE_PATH . "/{$name}");
|
|
||||||
}
|
|
||||||
throw new FileSystemException('Cannot extract source ' . $name, $e->getCode(), $e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据系统环境的不同,自动转换路径的分隔符
|
|
||||||
*
|
|
||||||
* @param string $path 路径
|
|
||||||
*/
|
|
||||||
public static function convertPath(string $path): string
|
|
||||||
{
|
|
||||||
if (str_starts_with($path, 'phar://')) {
|
|
||||||
return $path;
|
|
||||||
}
|
|
||||||
return str_replace('/', DIRECTORY_SEPARATOR, $path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 递归或非递归扫描目录,可返回相对目录的文件列表或绝对目录的文件列表
|
|
||||||
*
|
|
||||||
* @param string $dir 目录
|
|
||||||
* @param bool $recursive 是否递归扫描子目录
|
|
||||||
* @param bool|string $relative 是否返回相对目录,如果为true则返回相对目录,如果为false则返回绝对目录
|
|
||||||
* @param bool $include_dir 非递归模式下,是否包含目录
|
|
||||||
* @return array|false
|
|
||||||
* @since 2.5
|
|
||||||
*/
|
|
||||||
public static function scanDirFiles(string $dir, bool $recursive = true, bool|string $relative = false, bool $include_dir = false): bool|array
|
|
||||||
{
|
|
||||||
$dir = self::convertPath($dir);
|
|
||||||
// 不是目录不扫,直接 false 处理
|
|
||||||
if (!is_dir($dir)) {
|
|
||||||
logger()->warning('Scan dir failed, no such directory.');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
logger()->debug('scanning directory ' . $dir);
|
|
||||||
// 套上 zm_dir
|
|
||||||
$scan_list = scandir($dir);
|
|
||||||
if ($scan_list === false) {
|
|
||||||
logger()->warning('Scan dir failed, cannot scan directory: ' . $dir);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$list = [];
|
|
||||||
// 将 relative 置为相对目录的前缀
|
|
||||||
if ($relative === true) {
|
|
||||||
$relative = $dir;
|
|
||||||
}
|
|
||||||
// 遍历目录
|
|
||||||
foreach ($scan_list as $v) {
|
|
||||||
// Unix 系统排除这俩目录
|
|
||||||
if ($v == '.' || $v == '..') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$sub_file = self::convertPath($dir . '/' . $v);
|
|
||||||
if (is_dir($sub_file) && $recursive) {
|
|
||||||
# 如果是 目录 且 递推 , 则递推添加下级文件
|
|
||||||
$list = array_merge($list, self::scanDirFiles($sub_file, $recursive, $relative));
|
|
||||||
} elseif (is_file($sub_file) || is_dir($sub_file) && !$recursive && $include_dir) {
|
|
||||||
# 如果是 文件 或 (是 目录 且 不递推 且 包含目录)
|
|
||||||
if (is_string($relative) && mb_strpos($sub_file, $relative) === 0) {
|
|
||||||
$list[] = ltrim(mb_substr($sub_file, mb_strlen($relative)), '/\\');
|
|
||||||
} elseif ($relative === false) {
|
|
||||||
$list[] = $sub_file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取该路径下的所有类名,根据 psr-4 方式
|
|
||||||
*
|
|
||||||
* @param string $dir 目录
|
|
||||||
* @param string $base_namespace 基类命名空间
|
|
||||||
* @param null|mixed $rule 规则回调
|
|
||||||
* @param bool|string $return_path_value 是否返回路径对应的数组,默认只返回类名列表
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public static function getClassesPsr4(string $dir, string $base_namespace, mixed $rule = null, bool|string $return_path_value = false): array
|
|
||||||
{
|
|
||||||
$classes = [];
|
|
||||||
// 扫描目录,使用递归模式,相对路径模式,因为下面此路径要用作转换成namespace
|
|
||||||
$files = FileSystem::scanDirFiles($dir, true, true);
|
|
||||||
if ($files === false) {
|
|
||||||
throw new FileSystemException('Cannot scan dir files during get classes psr-4 from dir: ' . $dir);
|
|
||||||
}
|
|
||||||
foreach ($files as $v) {
|
|
||||||
$pathinfo = pathinfo($v);
|
|
||||||
if (($pathinfo['extension'] ?? '') == 'php') {
|
|
||||||
$path = rtrim($dir, '/') . '/' . rtrim($pathinfo['dirname'], './') . '/' . $pathinfo['basename'];
|
|
||||||
|
|
||||||
// 过滤不包含类的文件
|
|
||||||
$tokens = token_get_all(self::readFile($path));
|
|
||||||
$found = false;
|
|
||||||
foreach ($tokens as $token) {
|
|
||||||
if (!is_array($token)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ($token[0] === T_CLASS) {
|
|
||||||
$found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!$found) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($rule === null) { // 规则未设置回调时候,使用默认的识别过滤规则
|
|
||||||
/*if (substr(file_get_contents($dir . '/' . $v), 6, 6) == '#plain') {
|
|
||||||
continue;
|
|
||||||
}*/
|
|
||||||
if (file_exists($dir . '/' . $pathinfo['basename'] . '.ignore')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (mb_substr($pathinfo['basename'], 0, 7) == 'global_' || mb_substr($pathinfo['basename'], 0, 7) == 'script_') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} elseif (is_callable($rule) && !$rule($dir, $pathinfo)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$dirname = $pathinfo['dirname'] == '.' ? '' : (str_replace('/', '\\', $pathinfo['dirname']) . '\\');
|
|
||||||
$class_name = $base_namespace . '\\' . $dirname . $pathinfo['filename'];
|
|
||||||
if (is_string($return_path_value)) {
|
|
||||||
$classes[$class_name] = $return_path_value . '/' . $v;
|
|
||||||
} else {
|
|
||||||
$classes[] = $class_name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除目录及目录下的所有文件(危险操作)
|
|
||||||
*
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public static function removeDir(string $dir, bool $throw_on_fail = false): bool
|
|
||||||
{
|
|
||||||
$dir = FileSystem::convertPath($dir);
|
|
||||||
logger()->warning('Removing path recursively: "' . $dir . '"');
|
|
||||||
switch (PHP_OS_FAMILY) {
|
|
||||||
case 'Windows':
|
|
||||||
case 'WINNT':
|
|
||||||
case 'Cygwin':
|
|
||||||
f_exec('rmdir /s /g "' . $dir . '"', $out, $ret);
|
|
||||||
break;
|
|
||||||
case 'Darwin':
|
|
||||||
case 'Linux':
|
|
||||||
f_exec('rm -rf ' . escapeshellarg($dir), $out, $ret);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new FileSystemException('Unsupported OS type: ' . PHP_OS_FAMILY);
|
|
||||||
}
|
|
||||||
if ($ret !== 0 && $throw_on_fail) {
|
|
||||||
throw new FileSystemException('Cannot remove dir "' . $dir . '"');
|
|
||||||
}
|
|
||||||
return $ret === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function createDir(string $path): void
|
|
||||||
{
|
|
||||||
if (!is_dir($path) && !mkdir($path, 0755, true) && !is_dir($path)) {
|
|
||||||
throw new FileSystemException(sprintf('无法建立目录:%s', $path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\util;
|
|
||||||
|
|
||||||
use SPC\exception\ValidationException;
|
|
||||||
|
|
||||||
class ConfigValidator
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 验证 source.json
|
|
||||||
*
|
|
||||||
* @param array $data source.json 加载后的数据
|
|
||||||
* @throws ValidationException
|
|
||||||
*/
|
|
||||||
public static function validateSource(array $data): void
|
|
||||||
{
|
|
||||||
foreach ($data as $name => $src) {
|
|
||||||
isset($src['type']) || throw new ValidationException("source {$name} must have prop: [type]");
|
|
||||||
is_string($src['type']) || throw new ValidationException("source {$name} type prop must be string");
|
|
||||||
in_array($src['type'], ['filelist', 'git', 'ghtagtar', 'ghtar', 'ghrel', 'url']) || throw new ValidationException("source {$name} type [{$src['type']}] is invalid");
|
|
||||||
switch ($src['type']) {
|
|
||||||
case 'filelist':
|
|
||||||
isset($src['url'], $src['regex']) || throw new ValidationException("source {$name} needs [url] and [regex] props");
|
|
||||||
is_string($src['url']) && is_string($src['regex']) || throw new ValidationException("source {$name} [url] and [regex] must be string");
|
|
||||||
break;
|
|
||||||
case 'git':
|
|
||||||
isset($src['url'], $src['rev']) || throw new ValidationException("source {$name} needs [url] and [rev] props");
|
|
||||||
is_string($src['url']) && is_string($src['rev']) || throw new ValidationException("source {$name} [url] and [rev] must be string");
|
|
||||||
is_string($src['path'] ?? '') || throw new ValidationException("source {$name} [path] must be string");
|
|
||||||
break;
|
|
||||||
case 'ghtagtar':
|
|
||||||
case 'ghtar':
|
|
||||||
isset($src['repo']) || throw new ValidationException("source {$name} needs [repo] prop");
|
|
||||||
is_string($src['repo']) || throw new ValidationException("source {$name} [repo] must be string");
|
|
||||||
is_string($src['path'] ?? '') || throw new ValidationException("source {$name} [path] must be string");
|
|
||||||
break;
|
|
||||||
case 'ghrel':
|
|
||||||
isset($src['repo'], $src['match']) || throw new ValidationException("source {$name} needs [repo] and [match] props");
|
|
||||||
is_string($src['repo']) && is_string($src['match']) || throw new ValidationException("source {$name} [repo] and [match] must be string");
|
|
||||||
break;
|
|
||||||
case 'url':
|
|
||||||
isset($src['url']) || throw new ValidationException("source {$name} needs [url] prop");
|
|
||||||
is_string($src['url']) || throw new ValidationException("source {$name} [url] must be string");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param mixed $data
|
|
||||||
* @throws ValidationException
|
|
||||||
*/
|
|
||||||
public static function validateLibs($data, array $source_data = []): void
|
|
||||||
{
|
|
||||||
is_array($data) || throw new ValidationException('lib.json is broken');
|
|
||||||
foreach ($data as $name => $lib) {
|
|
||||||
isset($lib['source']) || throw new ValidationException("lib {$name} does not assign any source");
|
|
||||||
is_string($lib['source']) || throw new ValidationException("lib {$name} source must be string");
|
|
||||||
empty($source_data) || isset($source_data[$lib['source']]) || throw new ValidationException("lib {$name} assigns an invalid source: {$lib['source']}");
|
|
||||||
!isset($lib['lib-depends']) || !is_assoc_array($lib['lib-depends']) || throw new ValidationException("lib {$name} dependencies must be a list");
|
|
||||||
!isset($lib['lib-suggests']) || !is_assoc_array($lib['lib-suggests']) || throw new ValidationException("lib {$name} suggested dependencies must be a list");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function validateExts($data, array $source_data = []): void
|
|
||||||
{
|
|
||||||
is_array($data) || throw new ValidationException('ext.json is broken');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\util;
|
|
||||||
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\store\Config;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 依赖处理工具类,包含处理扩展、库的依赖列表顺序等
|
|
||||||
*/
|
|
||||||
class DependencyUtil
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 根据需要的 ext 列表获取依赖的 lib 列表,同时根据依赖关系排序
|
|
||||||
*
|
|
||||||
* @param array $exts 要获取 libs 依赖的列表
|
|
||||||
* @param array $additional_libs 额外要添加的库列表,用于激活 lib-suggests 触发的额外库特性
|
|
||||||
* @return array 返回一个包含三个数组的数组,第一个是排序后的 ext 列表,第二个是排序后的 lib 列表,第三个是没有传入但是依赖了的 ext 列表
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function getExtLibsByDeps(array $exts, array $additional_libs = []): array
|
|
||||||
{
|
|
||||||
// 先对扩展列表进行一个依赖筛选
|
|
||||||
$sorted = [];
|
|
||||||
$visited = [];
|
|
||||||
$not_included_exts = [];
|
|
||||||
foreach ($exts as $ext) {
|
|
||||||
if (!isset($visited[$ext])) {
|
|
||||||
self::visitExtDeps($ext, $visited, $sorted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$libs = $additional_libs;
|
|
||||||
// 遍历每一个 ext 的 libs
|
|
||||||
foreach ($sorted as $ext) {
|
|
||||||
if (!in_array($ext, $exts)) {
|
|
||||||
$not_included_exts[] = $ext;
|
|
||||||
}
|
|
||||||
foreach (Config::getExt($ext, 'lib-depends', []) as $lib) {
|
|
||||||
if (!in_array($lib, $libs)) {
|
|
||||||
$libs[] = $lib;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [$sorted, self::getLibsByDeps($libs), $not_included_exts];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据 lib 库的依赖关系进行一个排序,同时返回多出来的依赖列表
|
|
||||||
*
|
|
||||||
* @param array $libs 要排序的 libs 列表
|
|
||||||
* @return array 排序后的列表
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function getLibsByDeps(array $libs): array
|
|
||||||
{
|
|
||||||
$sorted = [];
|
|
||||||
$visited = [];
|
|
||||||
|
|
||||||
// 遍历所有
|
|
||||||
foreach ($libs as $lib) {
|
|
||||||
if (!isset($visited[$lib])) {
|
|
||||||
self::visitLibDeps($lib, $visited, $sorted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $sorted;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
private static function visitLibDeps(string $lib_name, array &$visited, array &$sorted): void
|
|
||||||
{
|
|
||||||
// 如果已经识别到了,那就不管
|
|
||||||
if (isset($visited[$lib_name])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$visited[$lib_name] = true;
|
|
||||||
// 遍历该依赖的所有依赖(此处的 getLib 如果检测到当前库不存在的话,会抛出异常)
|
|
||||||
foreach (Config::getLib($lib_name, 'lib-depends', []) as $dep) {
|
|
||||||
self::visitLibDeps($dep, $visited, $sorted);
|
|
||||||
}
|
|
||||||
$sorted[] = $lib_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
private static function visitExtDeps(string $ext_name, array &$visited, array &$sorted): void
|
|
||||||
{
|
|
||||||
if (isset($visited[$ext_name])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$visited[$ext_name] = true;
|
|
||||||
foreach (Config::getExt($ext_name, 'ext-depends', []) as $dep) {
|
|
||||||
self::visitExtDeps($dep, $visited, $sorted);
|
|
||||||
}
|
|
||||||
$sorted[] = $ext_name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,271 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\util;
|
|
||||||
|
|
||||||
use SPC\builder\BuilderBase;
|
|
||||||
use SPC\builder\macos\MacOSBuilder;
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\store\FileSystem;
|
|
||||||
|
|
||||||
class Patcher
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function patchPHPDepFiles(): void
|
|
||||||
{
|
|
||||||
$ver_file = SOURCE_PATH . '/php-src/main/php_version.h';
|
|
||||||
if (!file_exists($ver_file)) {
|
|
||||||
throw new FileSystemException('Patch failed, cannot find php source files');
|
|
||||||
}
|
|
||||||
$version_h = FileSystem::readFile(SOURCE_PATH . '/php-src/main/php_version.h');
|
|
||||||
preg_match('/#\s*define\s+PHP_MAJOR_VERSION\s+(\d+)\s+#\s*define\s+PHP_MINOR_VERSION\s+(\d+)\s+/m', $version_h, $match);
|
|
||||||
// $ver = "{$match[1]}.{$match[2]}";
|
|
||||||
|
|
||||||
logger()->info('Patching php');
|
|
||||||
|
|
||||||
$major_ver = $match[1] . $match[2];
|
|
||||||
$check = !defined('DEBUG_MODE') ? ' -q' : '';
|
|
||||||
// f_passthru('cd ' . SOURCE_PATH . '/php-src && git checkout' . $check . ' HEAD');
|
|
||||||
|
|
||||||
$patch_list = [
|
|
||||||
'static_opcache',
|
|
||||||
'static_extensions_win32',
|
|
||||||
'cli_checks',
|
|
||||||
'disable_huge_page',
|
|
||||||
'vcruntime140',
|
|
||||||
'win32',
|
|
||||||
'zend_stream',
|
|
||||||
];
|
|
||||||
$patch_list = array_merge($patch_list, match (PHP_OS_FAMILY) {
|
|
||||||
'Windows' => [
|
|
||||||
'cli_static',
|
|
||||||
],
|
|
||||||
'Darwin' => [
|
|
||||||
'macos_iconv',
|
|
||||||
],
|
|
||||||
default => [],
|
|
||||||
});
|
|
||||||
$patches = [];
|
|
||||||
$serial = ['80', '81', '82'];
|
|
||||||
foreach ($patch_list as $patchName) {
|
|
||||||
if (file_exists(SOURCE_PATH . "/php-src/sapi/micro/patches/{$patchName}.patch")) {
|
|
||||||
$patches[] = "sapi/micro/patches/{$patchName}.patch";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for ($i = array_search($major_ver, $serial, true); $i >= 0; --$i) {
|
|
||||||
$tryMajMin = $serial[$i];
|
|
||||||
if (!file_exists(SOURCE_PATH . "/php-src/sapi/micro/patches/{$patchName}_{$tryMajMin}.patch")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$patches[] = "sapi/micro/patches/{$patchName}_{$tryMajMin}.patch";
|
|
||||||
continue 2;
|
|
||||||
}
|
|
||||||
throw new RuntimeException("failed finding patch {$patchName}");
|
|
||||||
}
|
|
||||||
|
|
||||||
$patchesStr = str_replace('/', DIRECTORY_SEPARATOR, implode(' ', $patches));
|
|
||||||
|
|
||||||
f_passthru(
|
|
||||||
'cd ' . SOURCE_PATH . '/php-src && ' .
|
|
||||||
(PHP_OS_FAMILY === 'Windows' ? 'type' : 'cat') . ' ' . $patchesStr . ' | patch -p1'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function patchOpenssl3(): void
|
|
||||||
{
|
|
||||||
logger()->info('Patching PHP with openssl 3.0');
|
|
||||||
$openssl_c = file_get_contents(SOURCE_PATH . '/php-src/ext/openssl/openssl.c');
|
|
||||||
$openssl_c = preg_replace('/REGISTER_LONG_CONSTANT\s*\(\s*"OPENSSL_SSLV23_PADDING"\s*.+;/', '', $openssl_c);
|
|
||||||
file_put_contents(SOURCE_PATH . '/php-src/ext/openssl/openssl.c', $openssl_c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function patchSwow(): void
|
|
||||||
{
|
|
||||||
logger()->info('Patching swow');
|
|
||||||
if (PHP_OS_FAMILY === 'Windows') {
|
|
||||||
f_passthru('cd ' . SOURCE_PATH . '/php-src/ext && mklink /D swow swow-src\ext');
|
|
||||||
} else {
|
|
||||||
f_passthru('cd ' . SOURCE_PATH . '/php-src/ext && ln -s swow-src/ext swow');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function patchPHPBeforeConfigure(BuilderBase $builder): void
|
|
||||||
{
|
|
||||||
if ($builder->getExt('curl')) {
|
|
||||||
logger()->info('patching before-configure for curl checks');
|
|
||||||
$file1 = "AC_DEFUN([PHP_CHECK_LIBRARY], [\n $3\n])";
|
|
||||||
$files = FileSystem::readFile(SOURCE_PATH . '/php-src/ext/curl/config.m4');
|
|
||||||
$file2 = 'AC_DEFUN([PHP_CHECK_LIBRARY], [
|
|
||||||
save_old_LDFLAGS=$LDFLAGS
|
|
||||||
ac_stuff="$5"
|
|
||||||
|
|
||||||
save_ext_shared=$ext_shared
|
|
||||||
ext_shared=yes
|
|
||||||
PHP_EVAL_LIBLINE([$]ac_stuff, LDFLAGS)
|
|
||||||
AC_CHECK_LIB([$1],[$2],[
|
|
||||||
LDFLAGS=$save_old_LDFLAGS
|
|
||||||
ext_shared=$save_ext_shared
|
|
||||||
$3
|
|
||||||
],[
|
|
||||||
LDFLAGS=$save_old_LDFLAGS
|
|
||||||
ext_shared=$save_ext_shared
|
|
||||||
unset ac_cv_lib_$1[]_$2
|
|
||||||
$4
|
|
||||||
])dnl
|
|
||||||
])';
|
|
||||||
file_put_contents(SOURCE_PATH . '/php-src/ext/curl/config.m4', $file1 . "\n" . $files . "\n" . $file2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if ($builder->getExt('pdo_sqlite')) {
|
|
||||||
// FileSystem::replaceFile()
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function patchPHPConfigure(BuilderBase $builder): void
|
|
||||||
{
|
|
||||||
$frameworks = $builder instanceof MacOSBuilder ? ' ' . $builder->getFrameworks(true) . ' ' : '';
|
|
||||||
$curl = $builder->getExt('curl');
|
|
||||||
if ($curl) {
|
|
||||||
logger()->info('patching configure for curl checks');
|
|
||||||
FileSystem::replaceFile(
|
|
||||||
SOURCE_PATH . '/php-src/configure',
|
|
||||||
REPLACE_FILE_PREG,
|
|
||||||
'/-lcurl/',
|
|
||||||
$curl->getLibFilesString() . $frameworks
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$bzip2 = $builder->getExt('bz2');
|
|
||||||
if ($bzip2) {
|
|
||||||
logger()->info('patching configure for bzip2 checks');
|
|
||||||
FileSystem::replaceFile(
|
|
||||||
SOURCE_PATH . '/php-src/configure',
|
|
||||||
REPLACE_FILE_PREG,
|
|
||||||
'/-lbz2/',
|
|
||||||
$bzip2->getLibFilesString() . $frameworks
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$pdo_sqlite = $builder->getExt('pdo_sqlite');
|
|
||||||
if ($pdo_sqlite) {
|
|
||||||
logger()->info('patching configure for pdo_sqlite linking');
|
|
||||||
FileSystem::replaceFile(
|
|
||||||
SOURCE_PATH . '/php-src/configure',
|
|
||||||
REPLACE_FILE_PREG,
|
|
||||||
'/sqlite3_column_table_name=yes/',
|
|
||||||
'sqlite3_column_table_name=no'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
logger()->info('patching configure for disable capstone');
|
|
||||||
FileSystem::replaceFile(
|
|
||||||
SOURCE_PATH . '/php-src/configure',
|
|
||||||
REPLACE_FILE_PREG,
|
|
||||||
'/have_capstone="yes"/',
|
|
||||||
'have_capstone="no"'
|
|
||||||
);
|
|
||||||
if (property_exists($builder, 'arch') && php_uname('m') !== $builder->arch) {
|
|
||||||
// cross-compiling
|
|
||||||
switch ($builder->arch) {
|
|
||||||
case 'aarch64':
|
|
||||||
case 'arm64':
|
|
||||||
// almost all bsd/linux supports this
|
|
||||||
logger()->info('patching configure for shm mmap checks (cross-compiling)');
|
|
||||||
FileSystem::replaceFile(
|
|
||||||
SOURCE_PATH . '/php-src/configure',
|
|
||||||
REPLACE_FILE_PREG,
|
|
||||||
'/have_shm_mmap_anon=no/',
|
|
||||||
'have_shm_mmap_anon=yes'
|
|
||||||
);
|
|
||||||
FileSystem::replaceFile(
|
|
||||||
SOURCE_PATH . '/php-src/configure',
|
|
||||||
REPLACE_FILE_PREG,
|
|
||||||
'/have_shm_mmap_posix=no/',
|
|
||||||
'have_shm_mmap_posix=yes'
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 'x86_64':
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new RuntimeException('unsupported arch: ' . $builder->arch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public static function patchUnixLibpng(): void
|
|
||||||
{
|
|
||||||
FileSystem::replaceFile(
|
|
||||||
SOURCE_PATH . '/libpng/configure',
|
|
||||||
REPLACE_FILE_STR,
|
|
||||||
'-lz',
|
|
||||||
BUILD_LIB_PATH . '/libz.a'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public static function patchDarwinOpenssl11(): void
|
|
||||||
{
|
|
||||||
FileSystem::replaceFile(
|
|
||||||
SOURCE_PATH . '/openssl/test/v3ext.c',
|
|
||||||
REPLACE_FILE_STR,
|
|
||||||
'#include <stdio.h>',
|
|
||||||
'#include <stdio.h>' . PHP_EOL . '#include <string.h>'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function patchLinuxPkgConfig(string $path): void
|
|
||||||
{
|
|
||||||
logger()->info("fixing pc {$path}");
|
|
||||||
|
|
||||||
$workspace = BUILD_ROOT_PATH;
|
|
||||||
if ($workspace === '/') {
|
|
||||||
$workspace = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = file_get_contents($path);
|
|
||||||
$content = preg_replace('/^prefix=.+$/m', "prefix={$workspace}", $content);
|
|
||||||
$content = preg_replace('/^libdir=.+$/m', 'libdir=${prefix}/lib', $content);
|
|
||||||
$content = preg_replace('/^includedir=.+$/m', 'includedir=${prefix}/include', $content);
|
|
||||||
file_put_contents($path, $content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public static function patchLinuxConfigHeader(string $libc): void
|
|
||||||
{
|
|
||||||
switch ($libc) {
|
|
||||||
case 'musl_wrapper':
|
|
||||||
// bad checks
|
|
||||||
FileSystem::replaceFile(SOURCE_PATH . '/php-src/main/php_config.h', REPLACE_FILE_PREG, '/^#define HAVE_STRLCPY 1$/m', '');
|
|
||||||
FileSystem::replaceFile(SOURCE_PATH . '/php-src/main/php_config.h', REPLACE_FILE_PREG, '/^#define HAVE_STRLCAT 1$/m', '');
|
|
||||||
// no break
|
|
||||||
case 'musl':
|
|
||||||
FileSystem::replaceFile(SOURCE_PATH . '/php-src/main/php_config.h', REPLACE_FILE_PREG, '/^#define HAVE_FUNC_ATTRIBUTE_IFUNC 1$/m', '');
|
|
||||||
break;
|
|
||||||
case 'glibc':
|
|
||||||
// avoid lcrypt dependency
|
|
||||||
FileSystem::replaceFile(SOURCE_PATH . '/php-src/main/php_config.h', REPLACE_FILE_PREG, '/^#define HAVE_CRYPT 1$/m', '');
|
|
||||||
FileSystem::replaceFile(SOURCE_PATH . '/php-src/main/php_config.h', REPLACE_FILE_PREG, '/^#define HAVE_CRYPT_R 1$/m', '');
|
|
||||||
FileSystem::replaceFile(SOURCE_PATH . '/php-src/main/php_config.h', REPLACE_FILE_PREG, '/^#define HAVE_CRYPT_H 1$/m', '');
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new RuntimeException('not implemented');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\util;
|
|
||||||
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use ZM\Logger\ConsoleColor;
|
|
||||||
|
|
||||||
class UnixShell
|
|
||||||
{
|
|
||||||
private ?string $cd = null;
|
|
||||||
|
|
||||||
private bool $debug;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->debug = defined('DEBUG_MODE');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function cd(string $dir): UnixShell
|
|
||||||
{
|
|
||||||
logger()->info('Entering dir: ' . $dir);
|
|
||||||
$c = clone $this;
|
|
||||||
$c->cd = $dir;
|
|
||||||
return $c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function exec(string $cmd): UnixShell
|
|
||||||
{
|
|
||||||
/* @phpstan-ignore-next-line */
|
|
||||||
logger()->info(ConsoleColor::yellow('[EXEC] ') . ConsoleColor::green($cmd));
|
|
||||||
if ($this->cd !== null) {
|
|
||||||
$cmd = 'cd ' . escapeshellarg($this->cd) . ' && ' . $cmd;
|
|
||||||
}
|
|
||||||
if (!$this->debug) {
|
|
||||||
$cmd .= ' 1>/dev/null 2>&1';
|
|
||||||
}
|
|
||||||
f_passthru($cmd);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execWithResult(string $cmd, bool $with_log = true): array
|
|
||||||
{
|
|
||||||
if ($with_log) {
|
|
||||||
/* @phpstan-ignore-next-line */
|
|
||||||
logger()->info(ConsoleColor::blue('[EXEC] ') . ConsoleColor::green($cmd));
|
|
||||||
} else {
|
|
||||||
logger()->debug('Running command with result: ' . $cmd);
|
|
||||||
}
|
|
||||||
exec($cmd, $out, $code);
|
|
||||||
return [$code, $out];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
// 工作目录
|
|
||||||
use ZM\Logger\ConsoleLogger;
|
|
||||||
|
|
||||||
define('WORKING_DIR', getcwd());
|
|
||||||
const ROOT_DIR = __DIR__ . '/../..';
|
|
||||||
|
|
||||||
// 程序启动时间
|
|
||||||
define('START_TIME', microtime(true));
|
|
||||||
|
|
||||||
// 规定目录
|
|
||||||
define('BUILD_ROOT_PATH', is_string($a = getenv('BUILD_ROOT_PATH')) ? $a : (WORKING_DIR . '/buildroot'));
|
|
||||||
define('SOURCE_PATH', is_string($a = getenv('SOURCE_PATH')) ? $a : (WORKING_DIR . '/source'));
|
|
||||||
define('DOWNLOAD_PATH', is_string($a = getenv('DOWNLOAD_PATH')) ? $a : (WORKING_DIR . '/downloads'));
|
|
||||||
define('BUILD_LIB_PATH', is_string($a = getenv('INSTALL_LIB_PATH')) ? $a : (BUILD_ROOT_PATH . '/lib'));
|
|
||||||
const BUILD_DEPS_PATH = BUILD_ROOT_PATH;
|
|
||||||
define('BUILD_INCLUDE_PATH', is_string($a = getenv('INSTALL_INCLUDE_PATH')) ? $a : (BUILD_ROOT_PATH . '/include'));
|
|
||||||
define('SEPARATED_PATH', [
|
|
||||||
'/' . pathinfo(BUILD_LIB_PATH)['basename'], // lib
|
|
||||||
'/' . pathinfo(BUILD_INCLUDE_PATH)['basename'], // include
|
|
||||||
BUILD_ROOT_PATH,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 危险的命令额外用 notice 级别提醒
|
|
||||||
const DANGER_CMD = [
|
|
||||||
'rm',
|
|
||||||
'rmdir',
|
|
||||||
];
|
|
||||||
|
|
||||||
// 替换方案
|
|
||||||
const REPLACE_FILE_STR = 1;
|
|
||||||
const REPLACE_FILE_PREG = 2;
|
|
||||||
const REPLACE_FILE_USER = 3;
|
|
||||||
|
|
||||||
// 编译输出类型
|
|
||||||
const BUILD_MICRO_NONE = 0;
|
|
||||||
const BUILD_MICRO_ONLY = 1;
|
|
||||||
const BUILD_MICRO_BOTH = 2;
|
|
||||||
|
|
||||||
// 编译状态
|
|
||||||
const BUILD_STATUS_OK = 0;
|
|
||||||
const BUILD_STATUS_ALREADY = 1;
|
|
||||||
const BUILD_STATUS_FAILED = 2;
|
|
||||||
|
|
||||||
// 编译类型
|
|
||||||
const BUILD_TYPE_CLI = 1;
|
|
||||||
const BUILD_TYPE_MICRO = 2;
|
|
||||||
|
|
||||||
ConsoleLogger::$date_format = 'H:i:s';
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use SPC\util\UnixShell;
|
|
||||||
use ZM\Logger\ConsoleLogger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断传入的数组是否为关联数组
|
|
||||||
* @param mixed $array
|
|
||||||
*/
|
|
||||||
function is_assoc_array($array): bool
|
|
||||||
{
|
|
||||||
return is_array($array) && (!empty($array) && array_keys($array) !== range(0, count($array) - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 助手方法,返回一个 Logger 实例
|
|
||||||
*/
|
|
||||||
function logger(): LoggerInterface
|
|
||||||
{
|
|
||||||
global $ob_logger;
|
|
||||||
if ($ob_logger === null) {
|
|
||||||
return new ConsoleLogger();
|
|
||||||
}
|
|
||||||
return $ob_logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws \SPC\exception\RuntimeException
|
|
||||||
*/
|
|
||||||
function arch2gnu(string $arch): string
|
|
||||||
{
|
|
||||||
$arch = strtolower($arch);
|
|
||||||
return match ($arch) {
|
|
||||||
'x86_64', 'x64', 'amd64' => 'x86_64',
|
|
||||||
'arm64', 'aarch64' => 'aarch64',
|
|
||||||
default => throw new \SPC\exception\RuntimeException('Not support arch: ' . $arch),
|
|
||||||
// 'armv7' => 'arm',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function quote(string $str, string $quote = '"'): string
|
|
||||||
{
|
|
||||||
return $quote . $str . $quote;
|
|
||||||
}
|
|
||||||
|
|
||||||
function osfamily2dir(): string
|
|
||||||
{
|
|
||||||
return match (PHP_OS_FAMILY) {
|
|
||||||
/* @phpstan-ignore-next-line */
|
|
||||||
'Windows', 'WINNT', 'Cygwin' => 'windows',
|
|
||||||
'Darwin' => 'macos',
|
|
||||||
'Linux' => 'linux',
|
|
||||||
default => throw new \SPC\exception\RuntimeException('Not support os: ' . PHP_OS_FAMILY),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws \SPC\exception\RuntimeException
|
|
||||||
*/
|
|
||||||
function f_passthru(string $cmd): ?bool
|
|
||||||
{
|
|
||||||
$danger = false;
|
|
||||||
foreach (DANGER_CMD as $danger_cmd) {
|
|
||||||
if (str_starts_with($cmd, $danger_cmd . ' ')) {
|
|
||||||
$danger = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($danger) {
|
|
||||||
logger()->notice('Running dangerous command: ' . $cmd);
|
|
||||||
} else {
|
|
||||||
logger()->debug('Running command with direct output: ' . $cmd);
|
|
||||||
}
|
|
||||||
$ret = passthru($cmd, $code);
|
|
||||||
if ($code !== 0) {
|
|
||||||
throw new \SPC\exception\RuntimeException('Command run failed with code[' . $code . ']: ' . $cmd, $code);
|
|
||||||
}
|
|
||||||
return $ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
function f_exec(string $command, &$output, &$result_code)
|
|
||||||
{
|
|
||||||
logger()->debug('Running command (no output) : ' . $command);
|
|
||||||
return exec($command, $output, $result_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
function f_mkdir(string $directory, int $permissions = 0777, bool $recursive = false): bool
|
|
||||||
{
|
|
||||||
if (file_exists($directory)) {
|
|
||||||
logger()->debug("Dir {$directory} already exists, ignored");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
logger()->debug('Making new directory ' . ($recursive ? 'recursive' : '') . ': ' . $directory);
|
|
||||||
return mkdir($directory, $permissions, $recursive);
|
|
||||||
}
|
|
||||||
|
|
||||||
function shell(): UnixShell
|
|
||||||
{
|
|
||||||
return new UnixShell();
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/** @noinspection PhpComposerExtensionStubsInspection */
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
bcscale(3);
|
|
||||||
exit(bcdiv('105', '6.55957') === '16.007' ? 0 : 1);
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user