#!/bin/sh
# autopkgtest check: objects built with different -m flags must interoperate.
# A shared library built for the baseline architecture and an application
# built with a wider instruction set have to agree on how Eigen allocates,
# frees and aligns its heap buffers. See Debian bug #1064320.

set -e

WORKDIR=$(mktemp -d)
trap "rm -rf $WORKDIR" 0 INT QUIT ABRT PIPE TERM
cd "$WORKDIR"

# Extra flags for the "application" side. Only architectures where the
# instruction set actually changes Eigen's alignment are interesting; on the
# others the test still runs, just with identical flags on both sides.
case "$(dpkg-architecture -qDEB_HOST_ARCH_CPU 2>/dev/null || uname -m)" in
  amd64|x86_64|i386|i486|i586|i686) APPFLAGS="-mavx" ;;
  *)                                APPFLAGS="" ;;
esac

cat <<'EOF' > lib.cc
#include <Eigen/Core>

__attribute__((visibility("default"))) Eigen::MatrixXd* make_matrix() {
  Eigen::MatrixXd* m = new Eigen::MatrixXd(64, 64);
  m->setConstant(2.0);
  return m;
}

__attribute__((visibility("default"))) void scale_matrix(Eigen::MatrixXd* m) { *m = (*m) * 1.5; }
EOF

cat <<'EOF' > main.cc
#include <Eigen/Core>
#include <cstdio>
#include <cmath>
#include <cstdlib>

Eigen::MatrixXd* make_matrix();
void scale_matrix(Eigen::MatrixXd* m);

int main() {
  Eigen::MatrixXd* m = make_matrix();  // allocated by the library
  *m = (*m) * 2.0;                     // vectorized here, allocated there
  scale_matrix(m);
  Eigen::MatrixXd product = (*m) * (*m);
  const double expected = 64.0 * 64.0 * (2.0 * 2.0 * 1.5);
  if (std::fabs(m->sum() - expected) > 1e-6) {
    std::printf("wrong sum: %f, expected %f\n", m->sum(), expected);
    return 1;
  }
  if (product.rows() != 64 || product.cols() != 64) return 1;
  delete m;  // freed here, allocated by the library
  std::printf("ok\n");
  return 0;
}
EOF

EIGEN_CFLAGS=$(pkgconf --cflags eigen3)
CXXFLAGS=$(dpkg-buildflags --get CXXFLAGS)

# The library is built without CPU-specific options and exports no Eigen
# symbols, exactly like a library shipped in Debian.
g++ $EIGEN_CFLAGS $CXXFLAGS -fvisibility=hidden -fPIC -c -o lib.o lib.cc
g++ -shared -o libmixedflags.so lib.o
g++ $EIGEN_CFLAGS $CXXFLAGS $APPFLAGS -c -o main.o main.cc
g++ -o main main.o -L. -lmixedflags -Wl,-rpath,'$ORIGIN'

./main
