# -*- mode: cmake -*-
# bindings/ocaml/CMakeLists.txt
#
#
# Copyright (C) 2008 Andrew Ross
# Copyright (C) 2009 Hezekiah M. Carty
# Copyright (C) 2009-2018 Alan W. Irwin
#
# This file is part of PLplot.
#
# PLplot is free software; you can redistribute it and/or modify
# it under the terms of the GNU Library General Public License as published
# by the Free Software Foundation; version 2 of the License.
#
# PLplot 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 Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public License
# along with PLplot; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA

if(ENABLE_ocaml)

  # Need these escaped versions when there is a space in the full pathname of these variables.
  string(REPLACE " " "\\ " CMAKE_SOURCE_DIR_ESCAPED ${CMAKE_SOURCE_DIR})
  string(REPLACE " " "\\ " CMAKE_CURRENT_SOURCE_DIR_ESCAPED ${CMAKE_CURRENT_SOURCE_DIR})
  string(REPLACE " " "\\ " CMAKE_BINARY_DIR_ESCAPED ${CMAKE_BINARY_DIR})
  string(REPLACE " " "\\ " CMAKE_INSTALL_LIBDIR_ESCAPED ${CMAKE_INSTALL_LIBDIR})

  # Optionally build the Plcairo module
  add_subdirectory(plcairo)

  # optional command to check consistency of plplot_h.inc.
  if(GENERATE_PLPLOT_H_INC)
    add_custom_target(
      check_plplot_h.inc
      COMMAND ${CMAKE_COMMAND} -E echo "Check that ${CMAKE_CURRENT_SOURCE_DIR}/plplot_h.inc is consistent with what should be same file generated with ${CMAKE_CURRENT_SOURCE_DIR}/touchup.ml and ${CMAKE_CURRENT_SOURCE_DIR}/bindings/ocaml/plplot_h"
      COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/generated_plplot_h.inc
      # For space in pathname case quoted escaped touch.ml does not
      # work for some reason so must copy it to the WORKING_DIRECTORY.
      # Furthermore, for this same case must remove absolute directory
      # location from generated_plplot_h.inc.  But plplot_h is fine in
      # its present quoted and escaped form, go figure.
      COMMAND ${CMAKE_COMMAND} -E copy
      ${CMAKE_CURRENT_SOURCE_DIR}/touchup.ml
      ${CMAKE_CURRENT_BINARY_DIR}/touchup.ml
      # N.B. This only works on Debian if the libpcre-ocaml-dev package is installed.
      COMMAND ${OCAML} touchup.ml "${CMAKE_CURRENT_SOURCE_DIR_ESCAPED}/plplot_h" generated_plplot_h.inc
      COMMAND cmp ${CMAKE_CURRENT_SOURCE_DIR}/plplot_h.inc ${CMAKE_CURRENT_BINARY_DIR}/generated_plplot_h.inc
      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
      VERBATIM
      )

    add_dependencies(check_all check_plplot_h.inc)

  endif(GENERATE_PLPLOT_H_INC)

  #Detailed CMake logic to build ocaml bindings for PLplot.

  # camlidl produces most of the C and OCaml code required to bind PLplot

  # My (AWI) experiments show OCaml build tools such as ${CAMLIDL} and
  # ${OCAMLC} do work properly when their arguments refer to pathnames
  # with spaces, but it is necessary to both quote and escape those
  # blanks as appropriate.  To simplify this task, the general
  # approach I am taking below when running OCaml build tools as
  # COMMANDS for custom commands is to use the VERBATIM version of all
  # such custom commands; the quoted variables
  # ${CMAKE_SOURCE_DIR_ESCAPED} or ${CMAKE_CURRENT_SOURCE_DIR_ESCAPED}
  # when referring to source-tree locations, never using
  # ${CMAKE_CURRENT_BINARY_DIR} in wherever it occurs in an OCaml
  # build command (since the build is done in that directory), and the
  # quoted variable ${CMAKE_BINARY_DIR_ESCAPED} to help refer to other
  # build-tree locations used by OCaml build tools.  The result is
  # that the only files that need to be copied from anywhere in the
  # source tree to ${CMAKE_CURRENT_BINARY_DIR} are particular
  # ${CMAKE_CURRENT_SOURCE_DIR} files that are mentioned on the OCaml
  # build tool command line.

  # Generate build tree names of files generated by camlidl.
  set(camlidl_GENERATED_SOURCE)
  set(SUFFIX_LIST .mli .ml _stubs.c .h)

  foreach(SUFFIX IN LISTS SUFFIX_LIST)
    list(APPEND camlidl_GENERATED_SOURCE ${CMAKE_CURRENT_BINARY_DIR}/plplot_core${SUFFIX})
  endforeach(SUFFIX IN LISTS SUFFIX_LIST)
  #message(STATUS "DEBUG:camlidl_GENERATED_SOURCE = ${camlidl_GENERATED_SOURCE}")

  add_custom_command(
    OUTPUT
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.idl
    ${camlidl_GENERATED_SOURCE}
    COMMAND ${CMAKE_COMMAND} -E copy
    ${CMAKE_CURRENT_SOURCE_DIR}/plplot_core.idl
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.idl
    # -I "${CMAKE_CURRENT_SOURCE_DIR_ESCAPED}" required to get access to plplot_h.inc.
    COMMAND ${CAMLIDL} -I "${CMAKE_CURRENT_SOURCE_DIR_ESCAPED}" -header plplot_core.idl
    DEPENDS
    ${CMAKE_CURRENT_SOURCE_DIR}/plplot_core.idl
    ${CMAKE_CURRENT_SOURCE_DIR}/plplot_h.inc
    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
    VERBATIM
    )

  # ocamlc -c compiles *.c into *.o.
  add_custom_command(
    OUTPUT
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_core_stubs.o
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_impl.c
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_impl.o
    COMMAND ${OCAMLC} -ccopt -I${CAMLIDL_LIB_DIR} -c plplot_core_stubs.c
    COMMAND ${CMAKE_COMMAND} -E copy
    ${CMAKE_CURRENT_SOURCE_DIR}/plplot_impl.c
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_impl.c
    COMMAND ${OCAMLC} -ccopt "-I${CMAKE_SOURCE_DIR_ESCAPED}/include" -ccopt "-I${CMAKE_BINARY_DIR_ESCAPED}/include" -ccopt "-I${CMAKE_SOURCE_DIR_ESCAPED}/lib/qsastime" -ccopt "-I${CMAKE_BINARY_DIR_ESCAPED}/lib/qsastime" -ccopt -I../../include -ccopt -I../.. -ccopt -I${CAMLIDL_LIB_DIR} -ccopt -DPLPLOT_HAVE_CONFIG_H -c plplot_impl.c
    DEPENDS
    ${camlidl_GENERATED_SOURCE}
    ${CMAKE_CURRENT_SOURCE_DIR}/plplot_impl.c
    PLPLOT::plplot
    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
    VERBATIM
    )

  # Determine ocaml library flags for build tree and install tree.
  set(ocaml_LIBRARIES_FLAGS)
  set(installed_ocaml_LIBRARIES_FLAGS)
  if(NOT BUILD_SHARED_LIBS)
    # Order of these libraries matters for second use
    # of this list below.
    set(library_LIST PLPLOT::plplot PLPLOT::csirocsa PLPLOT::csironn PLPLOT::qsastime)
    if(PLD_cgm)
      list(APPEND library_LIST PLPLOT::nistcd)
    endif(PLD_cgm)

    foreach(library IN LISTS library_LIST)
      # N.B. the INTERFACE_LINK_LIBRARIES property refers to all libraries
      # that ${library} depends on, but not the library itself!
      get_target_property(LIBRARY_LIST ${library} INTERFACE_LINK_LIBRARIES)
      #message(STATUS "DEBUG: library = ${library} has INTERFACE_LINK_LIBRARIES property = ${LIBRARY_LIST}")
      list(APPEND ocaml_LIBRARIES_FLAGS ${LIBRARY_LIST})
    endforeach(library in LISTS library_LIST)

    # Get rid of internal symbolic targets and symbolic Qt5 targets from the list
    #message(STATUS "DEBUG: (original) ocaml_LIBRARIES_FLAGS = ${ocaml_LIBRARIES_FLAGS}")
    list(FILTER ocaml_LIBRARIES_FLAGS EXCLUDE REGEX "^PLPLOT::csirocsa$|^PLPLOT::csironn$|^PLPLOT::nistcd$|^PLPLOT::qsastime$|^Qt5::")
    #message(STATUS "DEBUG: (filtered) ocaml_LIBRARIES_FLAGS = ${ocaml_LIBRARIES_FLAGS}")

    # Add C++ libraries in case there is at least one C++ device
    # driver in libplplot.
    list(APPEND ocaml_LIBRARIES_FLAGS ${cxx_compiler_library_pathname_list})

    #message(STATUS "DEBUG: raw ocaml_LIBRARIES_FLAGS = ${ocaml_LIBRARIES_FLAGS}")

    # Add back actual list of Qt5 libraries to replace the symbolic
    # form of Qt5 libraries that were removed above.
    if(PLPLOT_USE_QT5)
      list(APPEND ocaml_LIBRARIES_FLAGS ${pc_qt_LIBRARIES_LIST})
      #message(STATUS "DEBUG: (Qt5 added) ocaml_LIBRARIES_FLAGS = ${ocaml_LIBRARIES_FLAGS}")
    endif(PLPLOT_USE_QT5)

    # There is a long-standing bug for cmake where the regexp "^[^-]"
    # acts the same as "[^-]", i.e., the starting anchor is ignored.
    # So workaround that bug by inserting an empty field to start the
    # list and then remove that empty field as the last step in
    # ocaml_LIBRARIES_FLAGS processing.
    set(ocaml_LIBRARIES_FLAGS ";${ocaml_LIBRARIES_FLAGS}")

    # Prepend all "-" options with -ccopt.
    string(REGEX REPLACE ";-" ";-ccopt;-" ocaml_LIBRARIES_FLAGS "${ocaml_LIBRARIES_FLAGS}")
    #message(STATUS "DEBUG: (\"-\" options processed) ocaml_LIBRARIES_FLAGS = ${ocaml_LIBRARIES_FLAGS}")

    # Prepend -cclib to every list item that does not start already with "-"
    string(REGEX REPLACE ";([^-])" ";-cclib;\\1" ocaml_LIBRARIES_FLAGS "${ocaml_LIBRARIES_FLAGS}")
    #message(STATUS "DEBUG: (inserted -cclib) ocaml_LIBRARIES_FLAGS = ${ocaml_LIBRARIES_FLAGS}")
    # Delete starting empty field.
    list(REMOVE_AT ocaml_LIBRARIES_FLAGS 0)
    #message(STATUS "DEBUG: (removed starting empty field) ocaml_LIBRARIES_FLAGS = ${ocaml_LIBRARIES_FLAGS}")

    # Installed version depends on install-tree locations for internal libraries
    # rather than build-tree locations so must use a distinct variable for
    # the installed case.
    set(installed_ocaml_LIBRARIES_FLAGS ${ocaml_LIBRARIES_FLAGS})

    # Order matters so prepend (N.B. in reverse order) plplot and the internal libraries that were removed in target-name form above to the list of FLAGS.

    if(PLD_cgm)
      set(ocaml_LIBRARIES_FLAGS -ccopt "-L${CMAKE_BINARY_DIR_ESCAPED}/lib/nistcd" -cclib -l${WRITEABLE_TARGET}nistcd ${ocaml_LIBRARIES_FLAGS})
      set(installed_ocaml_LIBRARIES_FLAGS -cclib -l${WRITEABLE_TARGET}nistcd ${installed_ocaml_LIBRARIES_FLAGS})
    endif(PLD_cgm)
    set(ocaml_LIBRARIES_FLAGS -ccopt "-L${CMAKE_BINARY_DIR_ESCAPED}/lib/qsastime" -cclib -l${WRITEABLE_TARGET}qsastime ${ocaml_LIBRARIES_FLAGS})
    set(installed_ocaml_LIBRARIES_FLAGS -cclib -l${WRITEABLE_TARGET}qsastime ${installed_ocaml_LIBRARIES_FLAGS})

    set(ocaml_LIBRARIES_FLAGS -ccopt "-L${CMAKE_BINARY_DIR_ESCAPED}/lib/nn" -cclib -l${WRITEABLE_TARGET}csironn ${ocaml_LIBRARIES_FLAGS})
    set(installed_ocaml_LIBRARIES_FLAGS -cclib -l${WRITEABLE_TARGET}csironn ${installed_ocaml_LIBRARIES_FLAGS})

    set(ocaml_LIBRARIES_FLAGS -ccopt "-L${CMAKE_BINARY_DIR_ESCAPED}/lib/csa" -cclib -l${WRITEABLE_TARGET}csirocsa ${ocaml_LIBRARIES_FLAGS})
    set(installed_ocaml_LIBRARIES_FLAGS -cclib -l${WRITEABLE_TARGET}csirocsa ${installed_ocaml_LIBRARIES_FLAGS})

    set(ocaml_LIBRARIES_FLAGS -ccopt "-L${CMAKE_BINARY_DIR_ESCAPED}/src" -cclib -l${WRITEABLE_TARGET}plplot ${ocaml_LIBRARIES_FLAGS})
    set(installed_ocaml_LIBRARIES_FLAGS -ccopt "-L${CMAKE_INSTALL_LIBDIR_ESCAPED}" -cclib -l${WRITEABLE_TARGET}plplot ${installed_ocaml_LIBRARIES_FLAGS})
    #message(STATUS "DEBUG: (internal libraries processed) ocaml_LIBRARIES_FLAGS = ${ocaml_LIBRARIES_FLAGS}")
  else(NOT BUILD_SHARED_LIBS)
    # Add plplot library.
    list(APPEND ocaml_LIBRARIES_FLAGS -ccopt "-L${CMAKE_BINARY_DIR_ESCAPED}/src" -cclib -l${WRITEABLE_TARGET}plplot)
    list(APPEND installed_ocaml_LIBRARIES_FLAGS -ccopt "-L${CMAKE_INSTALL_LIBDIR_ESCAPED}" -cclib -l${WRITEABLE_TARGET}plplot)
  endif(NOT BUILD_SHARED_LIBS)
  # ocamlmklib links *.o into *.so and *.a
  add_custom_command(
    OUTPUT
    ${CMAKE_CURRENT_BINARY_DIR}/dllplplot_stubs.so
    ${CMAKE_CURRENT_BINARY_DIR}/libplplot_stubs.a
    # N.B. every attempt to get rpath to work for dllplplot_stubs.so
    # generated by this command has failed (as measured by "dll -r
    # dllplplot_stubs.so" and "readelf -d dllplplot_stubs.so|grep -i
    # rpath") for the ocamlopt case including specifying rpath with
    # the -dllpath "${CMAKE_SOURCE_DIR_ESCAPED}/src" option or using
    # any other of the 4 aliases of this option according to the
    # ocamlmklib man page, or using a specific -ccopt "-Wl,-rpath
    # -Wl,${CMAKE_SOURCE_DIR_ESCAPED}/src" (a form that is known to
    # work for ocamlopt, and which the ocamlmklib documentation says
    # [apparently incorrectly] is passed on to both ocamlc and
    # ocamlopt as appropriate).  This failure is likely the cause
    # of the ldd -r errors for the ocaml examples unless they are created
    # with ocamlc or ocamlopt using the appropriate rpath option.
    COMMAND ${OCAMLMKLIB} -o plplot_stubs -L${CAMLIDL_LIB_DIR} -lcamlidl ${ocaml_LIBRARIES_FLAGS} plplot_core_stubs.o plplot_impl.o
    DEPENDS
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_core_stubs.o
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_impl.o
    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
    VERBATIM
    )

  add_custom_command(
    OUTPUT
    ${CMAKE_CURRENT_BINARY_DIR}/dllinstalled_plplot_stubs.so
    ${CMAKE_CURRENT_BINARY_DIR}/libinstalled_plplot_stubs.a
    # N.B. every attempt to get rpath to work for dllplplot_stubs.so
    # generated by this command has failed (as measured by "dll -r
    # dllplplot_stubs.so" and "readelf -d dllplplot_stubs.so|grep -i
    # rpath") for the ocamlopt case including specifying rpath with
    # the -dllpath "${CMAKE_SOURCE_DIR_ESCAPED}/src" option or using
    # any other of the 4 aliases of this option according to the
    # ocamlmklib man page, or using a specific -ccopt "-Wl,-rpath
    # -Wl,${CMAKE_SOURCE_DIR_ESCAPED}/src" (a form that is known to
    # work for ocamlopt, and which the ocamlmklib documentation says
    # [apparently incorrectly] is passed on to both ocamlc and
    # ocamlopt as appropriate).  This failure is likely the cause
    # of the ldd -r errors for the ocaml examples unless they are created
    # with ocamlc or ocamlopt using the appropriate rpath option.
    COMMAND ${OCAMLMKLIB} -o installed_plplot_stubs -L${CAMLIDL_LIB_DIR} -lcamlidl ${installed_ocaml_LIBRARIES_FLAGS} plplot_core_stubs.o plplot_impl.o
    DEPENDS
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_core_stubs.o
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_impl.o
    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
    VERBATIM
    )

  add_custom_target(target_lib_plplot_stubs
    DEPENDS
    ${CMAKE_CURRENT_BINARY_DIR}/dllplplot_stubs.so
    ${CMAKE_CURRENT_BINARY_DIR}/libplplot_stubs.a
    ${CMAKE_CURRENT_BINARY_DIR}/dllinstalled_plplot_stubs.so
    ${CMAKE_CURRENT_BINARY_DIR}/libinstalled_plplot_stubs.a
    )

  # ocamlc -c compiles *.mli into *.cmi
  add_custom_command(
    OUTPUT
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.cmi
    ${CMAKE_CURRENT_BINARY_DIR}/plplot.mli
    ${CMAKE_CURRENT_BINARY_DIR}/plplot.cmi
    COMMAND ${OCAMLC} -c plplot_core.mli
    # ocamlc *.mli source file must be in ${CMAKE_CURRENT_BINARY_DIR}.
    COMMAND ${CMAKE_COMMAND} -E copy
    ${CMAKE_CURRENT_SOURCE_DIR}/plplot.mli
    ${CMAKE_CURRENT_BINARY_DIR}/plplot.mli
    COMMAND ${OCAMLC} -c plplot.mli
    DEPENDS
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.mli
    ${CMAKE_CURRENT_SOURCE_DIR}/plplot.mli
    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
    VERBATIM
    )
  add_custom_target(target_plplot_cmi
    DEPENDS
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.cmi
    ${CMAKE_CURRENT_BINARY_DIR}/plplot.mli
    ${CMAKE_CURRENT_BINARY_DIR}/plplot.cmi
    )

  # Have separate custom command for this copy step because ${CMAKE_CURRENT_BINARY_DIR}/plplot.ml
  # used in two different custom commands below.
  add_custom_command(
    OUTPUT
    ${CMAKE_CURRENT_BINARY_DIR}/plplot.ml
    COMMAND ${CMAKE_COMMAND} -E copy
    ${CMAKE_CURRENT_SOURCE_DIR}/plplot.ml
    ${CMAKE_CURRENT_BINARY_DIR}/plplot.ml
    DEPENDS
    ${CMAKE_CURRENT_SOURCE_DIR}/plplot.ml
    VERBATIM
    )

  # ocamlc -c compiles  *.ml into *.cmo and simultaneously checks against
  # *.cmi produced from *.mli above.
  add_custom_command(
    OUTPUT
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.cmo
    ${CMAKE_CURRENT_BINARY_DIR}/plplot.cmo
    COMMAND ${OCAMLC} -c plplot_core.ml
    # ${CMAKE_CURRENT_BINARY_DIR}/plplot.ml created by previous custom command.
    COMMAND ${OCAMLC} -c plplot.ml
    DEPENDS
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.ml
    ${CMAKE_CURRENT_BINARY_DIR}/plplot.ml
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.cmi
    ${CMAKE_CURRENT_BINARY_DIR}/plplot.cmi
    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
    VERBATIM
    )
  add_custom_target(target_plplot_cmo
    DEPENDS
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.cmo
    ${CMAKE_CURRENT_BINARY_DIR}/plplot.cmo
    )

  # ocamlc -a -custom builds a *.cma library from *.cmo
  add_custom_command(
    OUTPUT
    ${CMAKE_CURRENT_BINARY_DIR}/plplot.cma
    COMMAND ${OCAMLC} -a -custom -o plplot.cma plplot_core.cmo plplot.cmo -dllib -lplplot_stubs -ccopt -L. -cclib -lplplot_stubs -ccopt -L${CAMLIDL_LIB_DIR} -cclib -lcamlidl ${ocaml_LIBRARIES_FLAGS}
    DEPENDS
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.cmo
    ${CMAKE_CURRENT_BINARY_DIR}/plplot.cmo
    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
    VERBATIM
    )

  add_custom_command(
    OUTPUT
    ${CMAKE_CURRENT_BINARY_DIR}/installed_plplot.cma
    COMMAND ${OCAMLC} -a -custom -o installed_plplot.cma plplot_core.cmo plplot.cmo -dllib -lplplot_stubs -ccopt -L. -cclib -lplplot_stubs -ccopt -L${CAMLIDL_LIB_DIR} -cclib -lcamlidl ${installed_ocaml_LIBRARIES_FLAGS}
    DEPENDS
    ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.cmo
    ${CMAKE_CURRENT_BINARY_DIR}/plplot.cmo
    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
    VERBATIM
    )

    add_custom_target(target_plplot_cma
    DEPENDS
    ${CMAKE_CURRENT_BINARY_DIR}/plplot.cma
    ${CMAKE_CURRENT_BINARY_DIR}/installed_plplot.cma
    )

  # These targets depend on common files in their respective
  # file-dependency chains.  Therefore, to avoid screwing up parallel
  # builds must serialize with these target depends.
  add_dependencies(target_plplot_cmi target_lib_plplot_stubs)
  add_dependencies(target_plplot_cmo target_plplot_cmi)
  add_dependencies(target_plplot_cma target_plplot_cmo)

  add_custom_target(plplot_ocaml ALL)

  if(OCAMLOPT)
    # ocamlopt compiles *.ml into *.o and *.cmx and simultaneously
    # checks against *.cmi produced from *.mli above.
    add_custom_command(
      OUTPUT
      ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.cmx
      ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.o
      ${CMAKE_CURRENT_BINARY_DIR}/plplot.cmx
      ${CMAKE_CURRENT_BINARY_DIR}/plplot.o
      COMMAND ${OCAMLOPT} -c plplot_core.ml
      # ${CMAKE_CURRENT_BINARY_DIR}/plplot.ml created by previous custom command.
      COMMAND ${OCAMLOPT} -c plplot.ml
      DEPENDS
      ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.ml
      ${CMAKE_CURRENT_BINARY_DIR}/plplot.ml
      ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.cmi
      ${CMAKE_CURRENT_BINARY_DIR}/plplot.cmi
      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
      VERBATIM
      )
    add_custom_target(target_plplot_cmx
      DEPENDS
      ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.cmx
      ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.o
      ${CMAKE_CURRENT_BINARY_DIR}/plplot.cmx
      ${CMAKE_CURRENT_BINARY_DIR}/plplot.o
      )

    # ocamlopt -a builds the libraries *.cmxa and *.a respectively from
    # the *.cmx and *.o files.  The plplot_stubs library also plays
    # a role.
    add_custom_command(
      OUTPUT
      ${CMAKE_CURRENT_BINARY_DIR}/plplot.cmxa
      ${CMAKE_CURRENT_BINARY_DIR}/plplot.a
      COMMAND ${OCAMLOPT} -a -o plplot.cmxa plplot_core.cmx plplot.cmx -ccopt -L. -cclib -lplplot_stubs -ccopt -L${CAMLIDL_LIB_DIR} -cclib -lcamlidl ${ocaml_LIBRARIES_FLAGS}
      DEPENDS
      ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.cmx
      ${CMAKE_CURRENT_BINARY_DIR}/plplot.cmx
      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
      VERBATIM
      )

    add_custom_command(
      OUTPUT
      ${CMAKE_CURRENT_BINARY_DIR}/installed_plplot.cmxa
      ${CMAKE_CURRENT_BINARY_DIR}/installed_plplot.a
      COMMAND ${OCAMLOPT} -a -o installed_plplot.cmxa plplot_core.cmx plplot.cmx -ccopt -L. -cclib -lplplot_stubs -ccopt -L${CAMLIDL_LIB_DIR} -cclib -lcamlidl ${installed_ocaml_LIBRARIES_FLAGS}
      DEPENDS
      ${CMAKE_CURRENT_BINARY_DIR}/plplot_core.cmx
      ${CMAKE_CURRENT_BINARY_DIR}/plplot.cmx
      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
      VERBATIM
      )

    add_custom_target(target_plplot_cmxa
      DEPENDS
      ${CMAKE_CURRENT_BINARY_DIR}/plplot.cmxa
      ${CMAKE_CURRENT_BINARY_DIR}/plplot.a
      ${CMAKE_CURRENT_BINARY_DIR}/installed_plplot.cmxa
      ${CMAKE_CURRENT_BINARY_DIR}/installed_plplot.a
      )

    # Must serialize these targets against highest dependency ocamlc
    # target, target_plplot_cma, because of common custom commands in
    # their file-dependency chains which would be screwed up in a
    # parallel build without this serialization.

    add_dependencies(target_plplot_cmx target_plplot_cma)
    add_dependencies(target_plplot_cmxa target_plplot_cmx)

    add_dependencies(plplot_ocaml target_plplot_cmxa)

    # Need to keep track of file dependencies since this is a custom target.
    set_property(GLOBAL PROPERTY FILES_plplot_ocaml
      ${CMAKE_CURRENT_BINARY_DIR}/plplot.cmxa
      ${CMAKE_CURRENT_BINARY_DIR}/plplot.a
      )
  else (OCAMLOPT)
    add_dependencies(plplot_ocaml target_plplot_cma)
    # Need to keep track of file dependencies since this is a custom target.
    set_property(GLOBAL PROPERTY FILES_plplot_ocaml
      ${CMAKE_CURRENT_BINARY_DIR}/plplot.cma
      )
  endif(OCAMLOPT)

  if(OCAMLDOC)
    # Build OCaml API reference documentation
    set(OCAMLDOC_FILE_LIST
      Plplot.Plot.html
      Plplot.Quick_plot.html
      Plplot.html
      index.html
      index_attributes.html
      index_class_types.html
      index_classes.html
      index_exceptions.html
      index_methods.html
      index_module_types.html
      index_modules.html
      index_types.html
      index_values.html
      style.css
      type_Plplot.Plot.html
      type_Plplot.Quick_plot.html
      type_Plplot.html
      )

    set(OCAMLDOC_FILES)
    foreach(html_file ${OCAMLDOC_FILE_LIST})
      list(APPEND OCAMLDOC_FILES ${CMAKE_CURRENT_BINARY_DIR}/${html_file})
    endforeach(html_file ${OCAMLDOC_FILE_LIST})
    # ocamldoc builds the module's documentation using specially formatted
    # comments in the source file.
    add_custom_command(
      OUTPUT ${OCAMLDOC_FILES}
      COMMAND ${OCAMLDOC} -html plplot.mli
      DEPENDS
      ${CMAKE_CURRENT_BINARY_DIR}/plplot.mli
      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
      VERBATIM
      )
    add_custom_target(target_build_ocaml_doc DEPENDS ${OCAMLDOC_FILES})
    # associated custom command has common file depends with custom command
    # that is associated with target_plplot_cmi.  Therefore must serialize
    # the two custom targets.
    add_dependencies(target_plplot_cmi target_build_ocaml_doc)
  endif(OCAMLDOC)

  # Basic build done, now trying to finish up by adapting bits
  # and pieces of old build procedure below.

  # Configure the META file
  configure_file(META.in ${CMAKE_CURRENT_BINARY_DIR}/META)

  # Most files should be installed in the plplot subdirectory

  # Install files that do not have to be renamed.
  install(FILES
    ${CMAKE_CURRENT_BINARY_DIR}/plplot.cmi
    ${CMAKE_CURRENT_BINARY_DIR}/plplot.mli
    ${CMAKE_CURRENT_BINARY_DIR}/META
    DESTINATION ${OCAML_INSTALL_DIR}/plplot
    )

  if(OCAMLOPT)
    install(FILES
      ${CMAKE_CURRENT_BINARY_DIR}/plplot.cmx
      DESTINATION ${OCAML_INSTALL_DIR}/plplot
      )
  endif(OCAMLOPT)

  # Install files that have to be renamed.
  install(FILES
    ${CMAKE_CURRENT_BINARY_DIR}/libinstalled_plplot_stubs.a
    DESTINATION ${OCAML_INSTALL_DIR}/plplot
    RENAME libplplot_stubs.a
    )

  install(FILES
    ${CMAKE_CURRENT_BINARY_DIR}/installed_plplot.cma
    DESTINATION ${OCAML_INSTALL_DIR}/plplot
    RENAME plplot.cma
    )

  if(OCAMLOPT)
    install(FILES
      ${CMAKE_CURRENT_BINARY_DIR}/installed_plplot.cmxa
      DESTINATION ${OCAML_INSTALL_DIR}/plplot
      RENAME plplot.cmxa
      )
    install(FILES
      ${CMAKE_CURRENT_BINARY_DIR}/installed_plplot.a
      DESTINATION ${OCAML_INSTALL_DIR}/plplot
      RENAME plplot.a
      )
  endif(OCAMLOPT)

  # Shared library stubs go in stublibs.  Use SO_PERMISSIONS to be
  # consistent with permissions used for other shared objects.
  install(
    FILES ${CMAKE_CURRENT_BINARY_DIR}/dllinstalled_plplot_stubs.so
    DESTINATION ${OCAML_INSTALL_DIR}/stublibs
    PERMISSIONS ${SO_PERMISSIONS}
    RENAME dllplplot_stubs.so
    )

  # Configure pkg-config *.pc file corresponding to plplot.cma
  # Nothing should have to be done here for the static case since
  # that should all be taken care of by the configuration of
  # plplot.pc.
  pkg_config_file("ocaml" "OCaml" " OCaml binding" "plplot" "" "")

endif(ENABLE_ocaml)
