omy / OMyExternal

# ==========================
# OMyExternal 
# ==========================
# Functions to integrate non-OMake projects

# Downloading
# ============================

#| Run wget and retrieve $(url) to $(dir)
#  If the file is already downloaded, does nothing.
WGet(url, dir) =
    arc=$(basename $(url))
    dst=$(dir)$(DIRSEP)$(arc)
    mkdir_if_not_exists($(dir))
    $(dst):
        if $(test -e $(dst))
          touch $(dst)
        else
          wget --no-check-certificate -O $(dst).tmp $(url); mv $(dst).tmp $(dst) # Damn it, ocamlcore.org!
    return $(dst)

# Files
# ============================

#| List up files in directory $(dir), without the prefix "$(dir)/"
Files(dir) =
    return $(removeprefix $(dir)/, $(find $(dir) -f {}))
    
#| Get the OCaml module paths from OCaml object and interface file names: x.cmo, y.cmx => x, y
OCamlModulesFromPath(files)=
    return $(set $(removesuffix $(filter %.cmi %.cmo %.cmx, $(files))))

# CR : It is not used
FindOCamlSpotFiles(dir, files)=
    candidates=$(OCamlModulesFromPath $(files))
    spots=$(find $(dir) -regex .*\.\(annot|spot|spit\)\$)

# Functions for `External` projects
# ============================

# General rule for commands
# ---------------------------------
# Do not use ``;`` for sequential execution of commands in ``CONFIGURE`` and ``INSTALL`` variables, since they ignore errors. Use ``&&`` instead::
# 
#     INSTALL=(cd $(EXTRACT_DIR); ./configure; make all; make install; echo done)
# 
# In the above, even if one of the commands fails, OMake does not notice it, since the last command ``echo done`` always succeeds. The following is better:: 
# 
#     INSTALL=(cd $(EXTRACT_DIR); ./configure && make all install && echo done)
 
#| Add a rule to install non-omake project.
#
#      Argument
#          PACK (mandatory)
#              Name of the package. Once installed, ``Installed($(PACK))`` is created.
#      Environments
#          URL (optional)
#              URL of the source
#          REQUIRED_PACKS (mandatory)
#              List of install mark files of required package: ex. REQUIRED_PACKS=$(Installed type-conv)
#          CONFIGURE (optional)
#              Configure command: ex. (cd $(EXTRACT_DIR); ./configure --prefix $PREFIX)
#              Command is executed at the directory where the function is called.
#          INSTALL (mandatory)
#              Install command: ex. (cd $(EXTRACT_DIR); make all install).
#              Command is executed at the directory where the function is called.
#          OBJS (optional?)
#              The list of files installed
#
#  CR jfuruse: this is pretty buggy
OCamlExternal(PACK) =
# build dir
    BUILD_DIR=_build

#    $(BUILD_DIR):
#        mkdir_if_not_exists($(BUILD_DIR))

    .PHONY: very-clean
    very-clean:
        rm -rf $(BUILD_DIR)

    SRCOMake=
    if $(not $(defined SRCS)):
        SRCOMake=$(BUILD_DIR)/sources
        export SRCOMake

    OBJOMake=
    if $(not $(defined OBJS)):
        OBJOMake=$(BUILD_DIR)/objects
        export OBJOMake

# ARC
    # adds rule for $(ARC)
    if $(not $(defined ARC)):
        ARC=$(WGet $(URL), $(BUILD_DIR))
        export ARC

    .PHONY: manual_download
    manual_download: $(ARC)

# EXTRACT and CONFIGURE
    EXTRACT_DIR=$(BUILD_DIR)/extract

    .PHONY: clean
    clean:
        rm -rf $(EXTRACT_DIR)

    ApplyPatch(patch)=
      cmd=patch -d $(EXTRACT_DIR)

    Extract(ARC)=
        println(!!! Extracting $(ARC))
        rm -rf $(EXTRACT_DIR)
        mkdir_if_not_exists($(EXTRACT_DIR))
        TarExtractAt($(ARC), $(EXTRACT_DIR))
        if $(defined PATCH_COMMAND)
          println(Running patch command $(PATCH_COMMAND))
          (cd $(EXTRACT_DIR); $(PATCH_COMMAND))
        return

    .PHONY: manual_extract
    manual_extract:
        Extract($(ARC))

    Configure(x)=
        if $(defined CONFIGURE):
            (cd $(EXTRACT_DIR); $(CONFIGURE))
        # Configure can make SRCOMake
        if $(SRCOMake)
            section:
                srcs=$(removeprefix $(EXTRACT_DIR), $(Files $(EXTRACT_DIR)))
                chan=$(fopen $(SRCOMake), w)
                fprintln($(chan), SRCS=$(string $(srcs)))
                close($(chan))
        return

    .PHONY: manual_configure
    manual_configure:
        Configure(0)

    Install(x)=
        (cd $(EXTRACT_DIR); $(INSTALL))
        # Install can make OBJOMake
        if $(OBJOMake)
            section:
                println(GET_OBJS)
                objs=$(GET_OBJS 0)
                println(Creating $(OBJOMake) = $(string $(objs)))
                chan=$(fopen $(OBJOMake), w)
                fprintln($(chan), OBJS=$(string $(objs)))
                close($(chan))
                println(Install=> $(string $(objs)))
                return $(objs)
        else
            println(Install: OBJOMake does not exist)

    .PHONY: manual_install
    manual_install:
        Install(0)
    
    .PHONY: manual_prepare
    manual_prepare: $(ARC) $(REQUIRED_PACKS)
        Extract($(ARC))
        Configure(0)
        Install(0)

    if $(not $(defined SRCS))
        SRCS=
        .INCLUDE: $(SRCOMake)
            mkdir_if_not_exists($(BUILD_DIR))
            touch $@
        SRCS=$(addprefix $(EXTRACT_DIR)/, $(SRCS))
        export SRCS

    if $(SRCS)
        $(SRCS) : $(ARC)
            Extract($(ARC))
            Configure(0)
            
    if $(not $(defined OBJS))
        OBJS=
        .INCLUDE: $(OBJOMake)
            mkdir_if_not_exists($(BUILD_DIR))
            touch $@
        export OBJS

    if $(SRCS)
        if $(OBJS)
            $(OBJS): $(REQUIRED_PACKS) $(SRCS)
                Install(0)
            $(INSTALLED)/$(PACK): $(OBJS)
                CreateInstalled($(PACK), $(OBJS))
        else 
            $(INSTALLED)/$(PACK) $(OBJOMake) : $(SRCS) $(REQUIRED_PACKS)
                Install(0)    
                CreateInstalled($(PACK), $(OBJS))
            .DEFAULT: $(OBJOMake)
    else
        if $(OBJS)
            $(OBJS): $(REQUIRED_PACKS) $(ARC)
                Extract($(ARC))
                Configure(0)
                Install(0) 
            $(INSTALLED)/$(PACK): $(OBJS)
                CreateInstalled($(PACK), $(OBJS))
        else
            $(INSTALLED)/$(PACK) $(OBJOMake): $(ARC) $(REQUIRED_PACKS)
                Extract($(ARC))
                Configure(0)
                OBJS=Install(0)    
                CreateInstalled($(PACK), $(OBJS))

    install: $(INSTALLED)/$(PACK)
    .DEFAULT: install

#| Add a rule to install non-omake OCaml package.
#
#      Argument
#          PACK (mandatory)
#              Name of the package. Once installed, ``Installed($(PACK))`` is created.
#      Environments
#          URL (optional)
#              URL of the source
#          REQUIRED_PACKS (mandatory)
#              List of install mark files of required package: ex. REQUIRED_PACKS=$(Installed type-conv)
#          CONFIGURE (optional)
#              Configure command: ex. (cd $(EXTRACT_DIR); ./configure --prefix $PREFIX)
#              Command is executed at the directory where the function is called.
#          INSTALL (mandatory)
#              Install command: ex. (cd $(EXTRACT_DIR); ocamlfind install ...).
#              Command is executed at the directory where the function is called.
#              ``ocamlfind remove $(PACK)`` is automatically done before the installation.
#          OBJS (pretty optional?)
#              The list of files installed
#
#  CR jfuruse: this is pretty buggy
OCamlExternalPack(PACK) =
     INSTALL=ocamlfind remove $(PACK); $(INSTALL); spotinstall $(PACK)
     GET_OBJS(dummy)=
         println(find $(OCAMLFIND_DESTDIR)/$(PACK))
         return $(addprefix \$\(OCAMLFIND_DESTDIR\)/\$\(PACK\)/, $(Files $(OCAMLFIND_DESTDIR)/$(PACK)))
     OCamlExternal($(PACK))

#| Returns true if $(file) has ://
is_url(file) =
  match $(file)
  case $'://'
    return true
  default
    return false
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.