# Copyright 2012 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Environment Variables (Optional):
#   MOD_PAGESPEED_DIR: absolute path to the mod_pagespeed/src directory
#   PSOL_BINARY: absolute path to pagespeed_automatic.a

mod_pagespeed_dir="${MOD_PAGESPEED_DIR:-unset}"
position_aux="${POSITION_AUX:-unset}"

if [ "$mod_pagespeed_dir" = "unset" ] ; then
  mod_pagespeed_dir="$ngx_addon_dir/psol/include"
  build_from_source=false

  if [ ! -e "$mod_pagespeed_dir" ] ; then
    echo "ngx_pagespeed: pagespeed optimization library not found:"
    echo ""
    echo "   You need to separately download the pagespeed library:"
    echo ""
    echo "     $ cd /path/to/ngx_pagespeed"
    echo "     $ wget https://dl.google.com/dl/page-speed/psol/1.11.33.4.tar.gz"
    echo "     $ tar -xzvf 1.11.33.4.tar.gz # expands to psol/"
    echo ""
    echo "   Or see the installation instructions:"
    echo "     https://github.com/pagespeed/ngx_pagespeed#how-to-build"
    exit 1
  fi

else
  build_from_source=true
fi

os_name='unknown_os'
arch_name='unknown_arch'
uname_os=`uname`
uname_arch=`uname -m`

if [ $uname_os = 'Linux' ]; then
  os_name='linux'
elif [ $uname_os = 'Darwin' ]; then
  os_name='mac'
else
  echo "OS not supported: $uname_os"
  exit 1
fi

if [ $uname_arch = 'x86_64' -o $uname_arch = 'amd64' ]; then
  arch_name='x64'
elif [ $uname_arch = 'x86_32' -o $uname_arch = 'i686' \
                              -o $uname_arch = 'i386' ]; then
  arch_name='ia32'
else
  echo "Architecture not supported: $uname_arch"
  exit 1
fi

if [ "$NGX_DEBUG" = "YES" ]; then
  buildtype=Debug
else
  buildtype=Release
fi

# If the compiler is gcc, we want to use g++ to link, if at all possible,
# so that -static-libstdc++ works.
# Annoyingly, the feature test doesn't even use $LINK for linking, so that
# needs an explicit -lstdc++
pagespeed_libs=
ps_maybe_gpp_base=`basename $CC| sed s/gcc/g++/`
ps_maybe_gpp="`dirname $CC`/$ps_maybe_gpp_base"
if [ -n "$NGX_GCC_VER" -a \( -x "$ps_maybe_gpp" \) ]; then
  LINK=$ps_maybe_gpp
fi
pagespeed_libs="-lstdc++"

# The compiler needs to know that __sync_add_and_fetch_4 is ok,
# and this requires an instruction that didn't exist on i586 or i386.
if [ "$uname_arch" = "i686" ]; then
  FLAG_MARCH='-march=i686'
fi

CFLAGS="$CFLAGS $FLAG_MARCH"

# For now, standardize on gcc-4.x ABI --- if we don't set this, people building
# with new gcc defaulting to gcc-5 C++11 ABI will have build trouble linking
# to our libpsol.a
# See https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html
CFLAGS="$CFLAGS -D_GLIBCXX_USE_CXX11_ABI=0"
CC_TEST_FLAGS="$CC_TEST_FLAGS -D_GLIBCXX_USE_CXX11_ABI=0"

case "$NGX_GCC_VER" in
  4.8*)
    # On GCC 4.8 and above, -Wall enables -Wunused-local-typedefs.  This breaks
    # on VerifySizesAreEqual in bit_cast in chromium/src/base/basictypes.h which
    # has a typedef that is intentionally unused.
    CFLAGS="$CFLAGS -Wno-unused-local-typedefs"

    # On GCC 4.8 and above, we get the following compiler warning:
    # chromium/src/base/memory/scoped_ptr.h:133:7: warning: declaration of ‘class scoped_ptr<C>’ [enabled by default]
    # Based on discussion at http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54055,
    # this is invalid code, but hasn't been fixed yet in chromium.
    # Unfortunately, there also does not appear to be a flag for just disabling
    # that warning, so we add Wno-error to override nginx's default -Werror
    # option.
    CFLAGS="$CFLAGS -Wno-error"
  ;;
esac

# workaround for a bug in nginx-1.9.11, see:
# http://hg.nginx.org/nginx/rev/ff1e625ae55b
NGX_VERSION=`grep nginx_version src/core/nginx.h | sed -e 's/^.* \(.*\)$/\1/'`
if [ "$NGX_VERSION" = "1009011" ]; then
    CFLAGS="$CFLAGS -Wno-write-strings"
fi

if [ "$WNO_ERROR" = "YES" ]; then
    CFLAGS="$CFLAGS -Wno-error"
fi

psol_binary="${PSOL_BINARY:-unset}"
if [ "$psol_binary" = "unset" ] ; then
  if $build_from_source ; then
    psol_binary="\
        $mod_pagespeed_dir/pagespeed/automatic/pagespeed_automatic.a"
  else
    psol_library_dir="$ngx_addon_dir/psol/lib/$buildtype/$os_name/$arch_name"
    psol_binary="$psol_library_dir/pagespeed_automatic.a"
  fi
fi

echo "mod_pagespeed_dir=$mod_pagespeed_dir"
echo "build_from_source=$build_from_source"

ngx_feature="psol"
ngx_feature_name=""
ngx_feature_run=no
ngx_feature_incs="
#include \"pagespeed/kernel/base/string.h\"
#include \"pagespeed/kernel/base/string_writer.h\"
#include \"pagespeed/kernel/base/null_message_handler.h\"
#include \"pagespeed/kernel/html/html_parse.h\"
#include \"pagespeed/kernel/html/html_writer_filter.h\"
"

pagespeed_include="\
  $mod_pagespeed_dir \
  $mod_pagespeed_dir/third_party/chromium/src \
  $mod_pagespeed_dir/third_party/google-sparsehash/src \
  $mod_pagespeed_dir/third_party/google-sparsehash/gen/arch/$os_name/$arch_name/include \
  $mod_pagespeed_dir/third_party/protobuf/src/src \
  $mod_pagespeed_dir/third_party/re2/src \
  $mod_pagespeed_dir/out/$buildtype/obj/gen \
  $mod_pagespeed_dir/out/$buildtype/obj/gen/protoc_out/instaweb \
  $mod_pagespeed_dir/third_party/apr/src/include \
  $mod_pagespeed_dir/third_party/aprutil/src/include \
  $mod_pagespeed_dir/third_party/apr/gen/arch/$os_name/$arch_name/include \
  $mod_pagespeed_dir/third_party/aprutil/gen/arch/$os_name/$arch_name/include \
  $mod_pagespeed_dir/url"
ngx_feature_path="$pagespeed_include"

pagespeed_libs="$psol_binary $pagespeed_libs -lrt -pthread -lm"
ngx_feature_libs="$pagespeed_libs"
ngx_feature_test="

  GoogleString output_buffer;
  net_instaweb::StringWriter write_to_string(&output_buffer);

  net_instaweb::NullMessageHandler handler;
  net_instaweb::HtmlParse html_parse(&handler);
  net_instaweb::HtmlWriterFilter html_writer_filter(&html_parse);

  html_writer_filter.set_writer(&write_to_string);
  html_parse.AddFilter(&html_writer_filter);

  html_parse.StartParse(\"http:example.com\");
  html_parse.ParseText(
      \"<html ><body ><h1 >Test</h1 ><p>Test Text</p></body></html>\n\");
  html_parse.FinishParse();

  printf(\"parsed as: %s\", output_buffer.c_str())"

# Test whether we have pagespeed and can compile and link against it.
. "$ngx_addon_dir/cpp_feature"

if [ $ngx_found = no ]; then
  cat << END
$0: error: module ngx_pagespeed requires the pagespeed optimization library.
Look in obj/autoconf.err for more details.
END
  exit 1
fi

ps_src="$ngx_addon_dir/src"
ngx_addon_name=ngx_pagespeed
NGX_ADDON_DEPS="$NGX_ADDON_DEPS \
$ps_src/log_message_handler.h \
$ps_src/ngx_base_fetch.h \
$ps_src/ngx_caching_headers.h \
$ps_src/ngx_event_connection.h \
$ps_src/ngx_fetch.h \
$ps_src/ngx_gzip_setter.h \
$ps_src/ngx_list_iterator.h \
$ps_src/ngx_message_handler.h \
$ps_src/ngx_pagespeed.h \
$ps_src/ngx_rewrite_driver_factory.h \
$ps_src/ngx_rewrite_options.h \
$ps_src/ngx_server_context.h \
$ps_src/ngx_url_async_fetcher.h \
$psol_binary"
NPS_SRCS=" \
$ps_src/log_message_handler.cc \
$ps_src/ngx_base_fetch.cc \
$ps_src/ngx_caching_headers.cc \
$ps_src/ngx_event_connection.cc \
$ps_src/ngx_fetch.cc \
$ps_src/ngx_gzip_setter.cc \
$ps_src/ngx_list_iterator.cc \
$ps_src/ngx_message_handler.cc \
$ps_src/ngx_pagespeed.cc \
$ps_src/ngx_rewrite_driver_factory.cc \
$ps_src/ngx_rewrite_options.cc \
$ps_src/ngx_server_context.cc \
$ps_src/ngx_url_async_fetcher.cc"
# Save our sources in a separate var since we may need it in config.make
PS_NGX_SRCS="$NGX_ADDON_SRCS \
$NPS_SRCS"

# Make pagespeed run immediately before gzip and Brotli.
if echo $HTTP_FILTER_MODULES | grep ngx_http_brotli_filter_module >/dev/null; then
  next=ngx_http_brotli_filter_module
elif [ $HTTP_GZIP = YES ]; then
  next=ngx_http_gzip_filter_module
else
  next=ngx_http_range_header_filter_module
fi

if [ -n "$ngx_module_link" ]; then
  # nginx-1.9.11+
  ngx_module_type=HTTP_FILTER
  ngx_module_name="ngx_pagespeed ngx_pagespeed_etag_filter"
  ngx_module_incs="$ngx_feature_path"
  ngx_module_deps=
  ngx_module_srcs="$NPS_SRCS"
  ngx_module_libs="$ngx_feature_libs"
  ngx_module_order="ngx_http_range_header_filter_module\
                    ngx_pagespeed_etag_filter\
                    ngx_http_gzip_filter_module \
                    ngx_http_brotli_filter_module \
                    ngx_pagespeed \
                    ngx_http_postpone_filter_module \
                    ngx_http_ssi_filter_module \
                    ngx_http_charset_filter_module \
                    ngx_http_xslt_filter_module \
                    ngx_http_image_filter_module \
                    ngx_http_sub_filter_module \
                    ngx_http_addition_filter_module \
                    ngx_http_gunzip_filter_module \
                    ngx_http_userid_filter_module \
                    ngx_http_headers_filter_module"

    . auto/module

    if [ $ngx_module_link != DYNAMIC ]; then
      # ngx_module_order doesn't work with static modules,
      # so we must re-order filters here.
      if [ "$position_aux" = "true" ] ; then
        HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES $ngx_addon_name"
      else
        HTTP_FILTER_MODULES=$(echo $HTTP_FILTER_MODULES \
                             | sed "s/ngx_pagespeed//" \
                             | sed "s/$next/$next ngx_pagespeed/")
      fi
      # Make the etag header filter run immediately before range header filter.
      HTTP_FILTER_MODULES=$(echo $HTTP_FILTER_MODULES \
                           | sed "s/ngx_pagespeed_etag_filter//" \
                           | sed "s/ngx_http_range_header_filter_module/ngx_http_range_header_filter_module ngx_pagespeed_etag_filter/")
    else
      # config.make is not executed for dynamic modules
      CFLAGS="$CFLAGS -Wno-c++11-extensions"
      if [ "$position_aux" = "true" ] ; then
        ngx_module_type=HTTP_AUX_FILTER
        ngx_module_order=""
      fi
    fi
else
  CORE_LIBS="$CORE_LIBS $pagespeed_libs"
  CORE_INCS="$CORE_INCS $pagespeed_include"
  NGX_ADDON_SRCS="$PS_NGX_SRCS"
  if [ "$position_aux" = "true" ] ; then
    HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES $ngx_addon_name"
  else
    HTTP_FILTER_MODULES=$(echo $HTTP_FILTER_MODULES | sed "s/$next/$next $ngx_addon_name/")
  fi

  # Make the etag header filter run immediately before range header filter.
  HTTP_FILTER_MODULES=$(echo $HTTP_FILTER_MODULES |\
    sed "s/ngx_http_range_header_filter_module/ngx_http_range_header_filter_module ngx_pagespeed_etag_filter/")
fi

echo "List of modules (in reverse order of applicability): "$HTTP_FILTER_MODULES

# Test whether the compiler is compatible
ngx_feature="psol-compiler-compat"
ngx_feature_name=""
ngx_feature_run=no
ngx_feature_incs=""
ngx_feature_path=""
ngx_feature_libs="-lstdc++"
ngx_feature_test="

#if defined(__clang__) && defined(__GLIBCXX__)
   // See https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html#abi.versioning 
   // for a list of various values of __GLIBCXX__. Note that they're not monotonic
   // with respect to version numbers.
   #if __GLIBCXX__ == 20120322  || __GLIBCXX__ == 20120614
      #error \"clang is using libstdc++ 4.7.0 or 4.7.1, which can cause binary incompatibility.\"
   #endif
#endif

#if !defined(__clang__) && defined(__GNUC__)
   #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)
      #error \"GCC < 4.8 no longer supported. Please use gcc >= 4.8 or clang >= 3.3\"
   #endif
#endif

#if defined(__clang__)
   #if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 3)
      #error \"Please use gcc >= 4.8 or clang >= 3.3\"
   #endif
#endif
"

. "$ngx_addon_dir/cpp_feature"

if [ $ngx_found = no ]; then
  cat << END
$0: error: module ngx_pagespeed requires gcc >= 4.8 or clang >= 3.3.
See https://developers.google.com/speed/pagespeed/module/build_ngx_pagespeed_from_source for some recommendations.
Look in objs/autoconf.err for more details.
END
  exit 1
fi

have=NGX_PAGESPEED . auto/have
