phpv8 / v8js

V8 Javascript Engine for PHP — This PHP extension embeds the Google V8 Javascript Engine
http://pecl.php.net/package/v8js
MIT License
1.83k stars 200 forks source link

Instructions for installing V8 on Alpine (GN/GYP) #275

Closed AlexMasterov closed 7 years ago

AlexMasterov commented 7 years ago

V8 (Alpine Linux)

make \
  native \
  library=shared \
  snapshot=off \
  werror=no

V8Js

./configure --with-v8js=/usr/local/v8

checking for libv8_libplatform.a... not found
checking for libv8_libbase.a... not found
checking for natives_blob.bin... not found

After compiling V8 5.6+, I found only libv8_base.a. This is a configuration problem with V8Js, or my build of V8? Same problem with the extension php-v8.

pinepain commented 7 years ago

@AlexMasterov v8 have you traced the issue? AFAIR, there was some changes in v8 build process and some target directories were renamed/moved. I build v8 for PPA, here is rules file, but the last version I tried was 5.4. Will give it (building v8) a look later today or at least this week. If there will be any updates from your side, please, let us know.

pinepain commented 7 years ago

It seems to be v8 build process was heavily changed, here is some discussion - https://github.com/Homebrew/homebrew-core/pull/7168.

pinepain commented 7 years ago

After spending whole evening with fresh v8 5.7.94 it's clear that build system and layout was changed significantly.

@stesie what approach do you follow in terms of supported v8 versions?

I guess building manual may be adapted according to that changes. However I'm not sure what direction v8 is moving. In php-v8 I serve build versions specially for my ext, and I can drop older v8 version support easily. But altering package building one more time (it was changed a bit before 5.4) doesn't look like a nice time spending.

AlexMasterov commented 7 years ago

@pinepain glad to see you here, thanks for the reply.

GYP is going to be deprecated, but it seems that GN is not compatible with Alpine:

/tmp/v8/buildtools/linux64 # ldd gn
        /lib64/ld-linux-x86-64.so.2 (0x7f841c7d8000)
        libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x7f841c7d8000)
        librt.so.1 => /lib64/ld-linux-x86-64.so.2 (0x7f841c7d8000)
        libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x7f841c487000)
        libm.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7f841c7d8000)
        libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7f841c7d8000)
        ld-linux-x86-64.so.2 => /lib/ld-linux-x86-64.so.2 (0x7f841c1fa000)
        libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x7f841bfe8000)
Error relocating gn: __sbrk: symbol not found
stesie commented 7 years ago

@AlexMasterov at least it seems like the GN binary shipped with V8 (via depot utils) isn't. You might wan to try to compile GN yourself and use that version instead.

AlexMasterov commented 7 years ago

@stesie I'm already trying to compile GN from source. (I'll be glad for any help here)

Build dependencies

$ apk add --update git make gcc g++ python tar wget bash re2c

Ninja

$ git clone -o v1.6.0 --depth 1 https://chromium.googlesource.com/external/martine/ninja /tmp/ninja
$ cd /tmp/ninja
$ /tmp/ninja/configure.py --bootstrap
$ export PATH="/tmp/ninja:$PATH"
$ ninja --version
1.6.0.git

GN

$ mkdir -p /tmp/gn-standalone
$ git clone --depth 1 https://chromium.googlesource.com/chromium/src/base /tmp/gn-standalone/base
$ git clone --depth 1 https://chromium.googlesource.com/chromium/src/build /tmp/gn-standalone/build
$ git clone --depth 1 https://chromium.googlesource.com/chromium/src/tools/gn /tmp/gn-standalone/tools/gn

$ cd /tmp/gn-standalone/tools/gn
$ ./bootstrap/bootstrap.py -s -vv

<...>
/tmp/gn-standalone/base/third_party/libevent/epoll.c:39:23: fatal error: sys/queue.h: No such file or directory
ninja: build stopped: subcommand failed.
Command '['ninja', '-C', '/tmp/tmpSYfW3p', '-v', 'gn']' returned non-zero exit status 1

$ find /tmp/gn-standalone/ -name "queue.h"
/tmp/gn-standalone/base/third_party/libevent/compat/sys/queue.h
stesie commented 7 years ago

I don't know alpine well enough (and haven't tried building GN myself), but bsd-compat-headers has the file. Maybe it helps ...

AlexMasterov commented 7 years ago

@stesie it helped. Thanks!

Search the contents of packages? :)

AlexMasterov commented 7 years ago

A new challenge for me. (it was easy on Debian)

[31/332] CXX base/debug/task_annotator.o
FAILED: c++ -MMD -MF base/debug/task_annotator.o.d  -I/tmp/tmpTBvi5G/gen -I/tmp/gn-standalone -DNO_TCMALLOC -D__STDC_FORMAT_MACROS -O2 -g0 -D_FILE_OFFSET_BITS=64 -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -pthread -pipe -fno-exceptions -std=c++11 -Wno-c++11-narrowing -c /tmp/gn-standalone/base/debug/task_annotator.cc -o base/debug/task_annotator.o
In file included from /tmp/tmpTBvi5G/gen/base/allocator/features.h:6:0,
                 from /tmp/gn-standalone/base/tracked_objects.h:17,
                 from /tmp/gn-standalone/base/debug/task_annotator.cc:11:
/tmp/gn-standalone/build/buildflag.h:45:66: error: missing binary operator before token "("
 #define BUILDFLAG(flag) (BUILDFLAG_CAT(BUILDFLAG_INTERNAL_, flag)())
                                                                  ^
/tmp/gn-standalone/base/tracked_objects.h:829:5: note: in expansion of macro 'BUILDFLAG'
 #if BUILDFLAG(ENABLE_MEMORY_TASK_PROFILER)
     ^~~~~~~~~
/tmp/gn-standalone/build/buildflag.h:45:66: error: missing binary operator before token "("
 #define BUILDFLAG(flag) (BUILDFLAG_CAT(BUILDFLAG_INTERNAL_, flag)())
                                                                  ^
/tmp/gn-standalone/base/tracked_objects.h:843:5: note: in expansion of macro 'BUILDFLAG'
 #if BUILDFLAG(ENABLE_MEMORY_TASK_PROFILER)
     ^~~~~~~~~
cc1plus: warning: unrecognized command line option '-Wno-c++11-narrowing'
[31/332] CXX base/files/important_file_writer.o
ninja: build stopped: subcommand failed.
Command '['ninja', '-C', '/tmp/tmpTBvi5G', 'gn']' returned non-zero exit status 1
stesie commented 7 years ago

I'd think that's a problem with the c++ compiler you're using (or more specifically the preprocessor); maybe it's an old version of gcc?

AlexMasterov commented 7 years ago

@stesie Alpine 3.5 release is coming soon. Tried "edge"..

gcc 6.2.1-r1

$ gcc --version
gcc (Alpine 6.2.1) 6.2.1 20160822
stesie commented 7 years ago

that shouldn't be too old :-)

pinepain commented 7 years ago

I finally make libv8-5.7 PPA. As of written, it has v8-5.7.202. This and all further versions will be co-installable: I switched installation path from /usr/lib to /opt/libv8-MAJOR.MINOR. Note, that this is vanilla build with ICU with external data file. d8 is also available for dev/desting/debugging purposes under /opt/libv8-MAJOR.MINOR/lib directory. As gn doesn't support host x32 linux, no more i386 builds, only amd64. If you need to tweak build and/or host it by yourself, feels free to use pinepain/ppa-packaging repo which provides all necessary information to get starting and build debs/publish sources to PPA.

For homebrew there is pinepain/devtools tap with v8@5.7 formula. Same here, this and all further formulae will be co-installable and keg-only, so use /usr/local/opt/v8@MAJOR.MINOR as a v8 installation path.

For my php-v8 extension I altered build script a bit:

  DESIRED_V8_VERSION=5.7

  # Path where v8 from packages we recommend are installed, it's /opt/libv8-MAJOR.MINOR on Ubuntu
  # and /usr/local/opt/v8@MAJOR.MINOR on macOS
  PRIORITY_SEARCH_PATH="/opt/libv8-${DESIRED_V8_VERSION} /usr/local/opt/v8@${DESIRED_V8_VERSION}"
  SEARCH_PATH="${PRIORITY_SEARCH_PATH} /usr/local /usr"

If anything, give a look to latest changes on config.m4 under php-v8 repo.

Hope you will find it useful.

AlexMasterov commented 7 years ago

@stesie, @pinepain please, need advice :confused:

Musl does not provide mallinfo. How to replace (patch) this?

malloc_dump_provider.cc

  struct mallinfo info = mallinfo();
  DCHECK_GE(info.arena + info.hblkhd, info.uordblks);
  // In case of Android's jemalloc |arena| is 0 and the outer pages size is
  // reported by |hblkhd|. In case of dlmalloc the total is given by
  // |arena| + |hblkhd|. For more details see link: http://goo.gl/fMR8lF.
  total_virtual_size = info.arena + info.hblkhd;
  resident_size = info.uordblks;
  // Total allocated space is given by |uordblks|.
  allocated_objects_size = info.uordblks;
pinepain commented 7 years ago

@AlexMasterov does alpine have working tcmalloc? It seems to be it can help to avoid mallinfo call.

AlexMasterov commented 7 years ago

@pinepain thanks for the reply.

It seems to me that no. And building from source is not trivial on Alpine. A ton of dependencies that also have problems when building.. (because based on glibc)

I'm trying to build the GN on Alpine, and patch needed for this.

AlexMasterov commented 7 years ago

I got some advice from the musl developers. But it seems they (Google?) try to do malloc interposition in a glibc specific way. I couldn't just get rid of mallinfo usage or dummy it out (eg. always print 0 byte is in use).

Now I'm looking for a way to disable those allocator hacks, and not getting a Segmentation fault. Also I have open an issue in V8, but it looks like the patch in the near future is not expected.

People who write build systems should learn to write portable code.. otherwise their build system will cause more problems than it solves. (introspective backtracing and malloc interposition is not possible to do portably and thus should be optional)

build.log

[337/337] c++ -pthread -o gn -Wl,--start-group tools/gn/gn_main.o libevent.a base.a xdg_user_dirs.a gn_lib.a dynamic_annotations.a -Wl,--end-group -lrt -latomic
FAILED: gn
c++ -pthread -o gn -Wl,--start-group tools/gn/gn_main.o libevent.a base.a xdg_user_dirs.a gn_lib.a dynamic_annotations.a -Wl,--end-group -lrt -latomic
base/debug/stack_trace_posix.o: In function `base::debug::EnableInProcessStackDumping()':
stack_trace_posix.cc:(.text+0x220): undefined reference to `backtrace'
base/debug/stack_trace_posix.o: In function `base::debug::StackTrace::StackTrace()':
stack_trace_posix.cc:(.text+0x31a): undefined reference to `backtrace'
base/debug/stack_trace_posix.o: In function `base::debug::(anonymous namespace)::ProcessBacktrace(void* const*, unsigned long, base::debug::(anonymous namespace)::BacktraceOutputHandler*)':
stack_trace_posix.cc:(.text+0x548): undefined reference to `backtrace_symbols'
base/debug/stack_trace_posix.o: In function `base::debug::(anonymous namespace)::StackDumpSignalHandler(int, siginfo_t*, void*)':
stack_trace_posix.cc:(.text+0x93a): undefined reference to `backtrace'
base/allocator/allocator_shim_default_dispatch_to_glibc.o: In function `(anonymous namespace)::GlibcFree(base::allocator::AllocatorDispatch const*, void*)':
allocator_shim_default_dispatch_to_glibc.cc:(.text+0x14): undefined reference to `__libc_free'
base/allocator/allocator_shim_default_dispatch_to_glibc.o: In function `(anonymous namespace)::GlibcRealloc(base::allocator::AllocatorDispatch const*, void*, unsigned long)':
allocator_shim_default_dispatch_to_glibc.cc:(.text+0x27): undefined reference to `__libc_realloc'
base/allocator/allocator_shim_default_dispatch_to_glibc.o: In function `(anonymous namespace)::GlibcMemalign(base::allocator::AllocatorDispatch const*, unsigned long, unsigned long)':
allocator_shim_default_dispatch_to_glibc.cc:(.text+0x37): undefined reference to `__libc_memalign'
base/allocator/allocator_shim_default_dispatch_to_glibc.o: In function `(anonymous namespace)::GlibcCalloc(base::allocator::AllocatorDispatch const*, unsigned long, unsigned long)':
allocator_shim_default_dispatch_to_glibc.cc:(.text+0x47): undefined reference to `__libc_calloc'
base/allocator/allocator_shim_default_dispatch_to_glibc.o: In function `(anonymous namespace)::GlibcMalloc(base::allocator::AllocatorDispatch const*, unsigned long)':
allocator_shim_default_dispatch_to_glibc.cc:(.text+0x54): undefined reference to `__libc_malloc'
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
Command '['ninja', '-C', '/tmp/tmp97qKAr', '-v', 'gn']' returned non-zero exit status 1
AlexMasterov commented 7 years ago

I finally got V8 (5.6+) on Alpine. I also tested some build arguments that can speed up the compilation, and the V8. Now I want to create a package for Alpine with gn, and probably v8.

@stesie, @pinepain Does it make sense to send a PR with installation instruction? (GN/GYP on Alpine)

stesie commented 7 years ago

Congrats @AlexMasterov, this is very good news

Are you going to publish a docker base image with it? I suppose that's why you're so much into Alpine :)

... and sure, if you'd like to provide some build instructions I'll happily merge them. (Or link to Dockerfile, image, etc.)

AlexMasterov commented 7 years ago

@stesie Of course, alpine-libv8.

How to use it as a factory

docker build --build-arg V8_VERSION=5.7.455 --build-arg V8_DIR=/usr/local/v8 .

docker-compose

build:
  context: ./alpine-libv8
  args:
    - V8_VERSION=5.7.455
    - V8_DIR=/usr/local/v8

Extract

docker run -v $(pwd):/archive alpine_libv8 sh -c 'tar cvzf /archive/alpine-libv8-${V8_VERSION}.tar.gz -C ${V8_DIR} .'

Usage

# ADD alpine-libv8-5.7.455.tar.gz /usr/local/v8
V8_SOURCE="https://www.dropbox.com/s/f1xd788tjccfnc6/alpine-libv8-5.7.455.tar.gz"
V8_DIR="/usr/local/v8"
mkdir -p ${V8_DIR}
curl -fSL --connect-timeout 30 ${V8_SOURCE} | tar xz -C ${V8_DIR}

# v8js
git clone -b php7 --depth 1 https://github.com/preillyme/v8js.git /tmp/v8js
cd /tmp/v8js
phpize
./configure --with-v8js=${V8_DIR}
make
make install
AlexMasterov commented 7 years ago

I think it's the easiest way to use V8 on Alpine. Ideally, gn and v8 should be a Alpine package.

Now, I'm hesitant to write in detail about the installation GN on Alpine, patches, etc. Who is interested? Much easier to use ready-made binary and wait for a Alpine package.

I need advice on detailing.

stesie commented 7 years ago

@AlexMasterov I think that linking to the Dockerfile is enough as it is exactly what you need, a recipe on how to build it. I actually even like to google for Dockerfiles if I'm just willing to install off docker ... The README already has some links to docker, feel free to add yours there

With the Dockerfile you've linked to I personally dislike that it loads some binaries from dropbox and even more severe that it does that without certificate checks. But I think that's just work in progress and you're following up packaging gn for alpine even also!?

AlexMasterov commented 7 years ago

With the Dockerfile you've linked to I personally dislike that it loads some binaries from dropbox..

I agree with you. I can return the building stage (this includes patches), but then Dockerfile will look a bit verbose.

..and even more severe that it does that without certificate checks.

Here just need to install ca-certificates.

But I think that's just work in progress and you're following up packaging gn for alpine even also!?

By this weekend, I hope. It looks not difficult.

joehoyle commented 6 years ago

Hey @AlexMasterov did you ever managed to do pre-built packages for Alpine?

milesrichardson commented 6 years ago

Also really want to use this dockerfile but not with the dropbox link. Why is that necessary? Is the build process for alpine-gn documented somewhere?

stesie commented 6 years ago

@milesrichardson in his repository (history) there's some documentation on how it's built: https://github.com/AlexMasterov/dockerfiles/blob/912ffd01c5a848045b7235fc326275424512e095/alpine-v8-lib/Dockerfile#L26-L48

Maybe you'd like to fork his repo and integrate it. Yet usually building GN is a bit tedious since you need to check out from Chromium repos.

So it might be wise to use multi-stage docker builds

nathanielks commented 5 years ago

For others interested in how to build your own PHP images using @AlexMasterov's libv8 image, you can leverage multi-stage builds to do the following:

# Define versions used to select image versions
# (ARGs declared before FROM can't be used outside of FROMs)
ARG FROM_V8=6.6
ARG FROM_ALPINE=
ARG FROM_PHP=7.0

# Compress libv8 and save for later
FROM alexmasterov/alpine-libv8:$FROM_V8 as v8build
RUN tar cvzf /tmp/libv8.tar.gz -C ${V8_DIR} .

# Build PHP Image
FROM php:${FROM_PHP}-fpm-alpine${FROM_ALPINE}

COPY --from=v8build /tmp/libv8.tar.gz /tmp/libv8.tar.gz

# Install build dependencies
RUN apk add -u --no-cache --virtual .build-deps \
        $PHPIZE_DEPS \
        zlib-dev \
        g++ \
        make \

    # V8JS
    && export V8_DIR=/usr/local/v8 \
    && mkdir -p $V8_DIR \
    && tar xzvf /tmp/libv8.tar.gz -C $V8_DIR \
    && echo $V8_dir | pecl install v8js \
    && docker-php-ext-enable v8js \
    && rm -rf /tmp/libv8.tar.gz \

    # Cleanup
    && apk del .build-deps
ghost commented 5 years ago

Thanks, @nathanielks but seems that doesn't work for V8 versions 7.0, 7.1 and 7.2 with PHP 7.2, I receive this error during: "echo $V8_dir | pecl install v8js":

make: *** [Makefile:208: v8js_array_access.lo] Error 1
ERROR: `make' failed

happen only to me?

nathanielks commented 5 years ago

@CDNRocket no, you're not the only one. I'm not able to get V8 7.x+ to build with any version of php. I was able to get 6.9 to build, though:

docker build --build-arg FROM_V8=6.9 --build-arg FROM_PHP=7.2 -t php-v8-72-69 .

After some searching, I was able to find an issue discussing this problem: https://github.com/phpv8/v8js/issues/374. A fix has since been merged into the php7 branch, on 6 Nov 2018. The problem is the last v8js release was 2.1 on 7 Jan 2018, so there's no pre-compiled version of the v8js php extension. If you wish to use a version of V8 greater than 6.9, you'll need to compile the v8js php extension yourself and not install it via pecl.