GEDLIB  1.0
install.py
Go to the documentation of this file.
1 #//////////////////////////////////////////////////////////////////////////#
2 # #
3 # Copyright (C) 2018 by David B. Blumenthal #
4 # #
5 # This file is part of GEDLIB. #
6 # #
7 # GEDLIB is free software: you can redistribute it and/or modify it #
8 # under the terms of the GNU Lesser General Public License as published #
9 # by the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
11 # #
12 # GEDLIB is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU Lesser General Public License for more details. #
16 # #
17 # You should have received a copy of the GNU Lesser General Public #
18 # License along with GEDLIB. If not, see <http://www.gnu.org/licenses/>. #
19 # #
20 #//////////////////////////////////////////////////////////////////////////#
21 
22 
33 
34 '''Installs GEDLIB and its dependencies.'''
35 
36 from subprocess import call
37 import argparse
38 import shutil
39 import os.path
40 import glob
41 
42 def append_ged_env_hpp(identifier, node_id_type, node_label_type, edge_label_type):
43  append = ""
44  append = append + "\n";
45  append = append + "#ifdef " + identifier.upper() + "_GEDLIB_SHARED\n"
46  append = append + "#ifndef SRC_ENV_GED_ENV_" + identifier.upper() + "_CPP_\n"
47  append = append + "extern template class GEDEnv<" + node_id_type + ", " + node_label_type + ", " + edge_label_type + ">;\n"
48  append = append + "#endif /* SRC_ENV_GED_ENV_" + identifier.upper() + "_CPP_ */\n"
49  append = append + "#endif /*" + identifier.upper() + "_GEDLIB_SHARED */\n"
50  delete_line = 0
51  temp = open("temp", "wb")
52  with open("src/env/ged_env.hpp", "r") as f: for line in f:
53  if line.startswith("#ifdef ") and not line.startswith("#ifdef GXL_GEDLIB_SHARED"):
54  delete_line = 6
55  if line.startswith("#endif /* GXL_GEDLIB_SHARED */"):
56  line = line + append
57  if delete_line <= 0:
58  temp.write(line)
59  delete_line = delete_line - 1
60  temp.close()
61  shutil.move("temp", "src/env/ged_env.hpp")
62 
63 def append_cmake_lists(identifier):
64  append = ""
65  append = append + "\n"
66  append = append + "add_library(" + identifier.lower() + "gedlib SHARED env/ged_env." + identifier.lower() + ".cpp)\n"
67  append = append + "set_target_properties(" + identifier.lower() + "gedlib PROPERTIES SUFFIX \".so\")\n"
68  append = append + "target_link_libraries(" + identifier.lower() + "gedlib nomad doublefann svm)\n"
69  append = append + "if(APPLE)\n"
70  append = append + " add_custom_command(TARGET " + identifier.lower() + "gedlib POST_BUILD COMMAND install_name_tool -change libnomad.so ${NOMAD_HOME}/lib/libnomad.so ${LIBRARY_OUTPUT_PATH}/lib" + identifier.lower() + "gedlib.so)\n"
71  append = append + " add_custom_command(TARGET " + identifier.lower() + "gedlib POST_BUILD COMMAND install_name_tool -change libdoublefann.2.dylib ${FANN_HOME}/lib/libdoublefann.2.dylib ${LIBRARY_OUTPUT_PATH}/lib" + identifier.lower() + "gedlib.so)\n"
72  append = append + "add_custom_command(TARGET " + identifier.lower() + "gedlib POST_BUILD COMMAND install_name_tool -change libsvm.so ${LIBSVM_HOME}/libsvm.so ${LIBRARY_OUTPUT_PATH}/lib" + identifier.lower() + "gedlib.so)\n"
73  append = append + "endif()\n"
74  delete_line = 0
75  temp = open("temp", "wb")
76  with open("src/CMakeLists.txt", "r") as f:
77  for line in f:
78  if line.startswith("add_library(") and not line.startswith("add_library(gxlgedlib"):
79  delete_line = 9
80  if line.startswith("endif()"):
81  line = line + append
82  if delete_line <= 0:
83  temp.write(line)
84  delete_line = delete_line - 1
85  temp.close()
86  shutil.move("temp", "src/CMakeLists.txt")
87 
88 def create_template_instantiation(identifier, node_id_type, node_label_type, edge_label_type):
89  with open("src/env/ged_env." + identifier.lower() + ".cpp", "w") as f:
90  f.write("/*!\n")
91  f.write(" * @file ged_env." + identifier.lower() + ".cpp\n")
92  f.write(" * @brief ged::GEDEnv<" + node_id_type + ", " + node_label_type + ", " + edge_label_type + "> template instantiation.\n")
93  f.write(" */\n")
94  f.write("\n")
95  f.write("#ifndef SRC_ENV_GED_ENV_" + identifier.upper() + "_CPP_\n")
96  f.write("#define SRC_ENV_GED_ENV_" + identifier.upper() + "_CPP_\n")
97  f.write("\n")
98  f.write("#include \"ged_env.hpp\"\n")
99  f.write("\n")
100  f.write("namespace ged {\n")
101  f.write("\n")
102  f.write("template class GEDEnv<" + node_id_type + ", " + node_label_type + ", " + edge_label_type + ">;\n")
103  f.write("\n")
104  f.write("}\n")
105  f.write("\n")
106  f.write("#endif /* SRC_ENV_GED_ENV_" + identifier.upper() + "_CPP_ */\n")
107 
108 def parse_custom_types(custom_types):
109  if len(custom_types.split(",")) != 4:
110  raise Exception("Invalid argument \"" + args.lib + "\" for option lib. Usage: python install.py [--lib gxl|<indentifier-different-from-'gxl'>,<node-ID-type>,<node-label-type>,<edge-label-type>] [...]")
111  return custom_types.split(",")
112 
113 def create_directories():
114  print("\n***** Create directories for shared libraries, executables and output. *****")
115  commands = "mkdir -p lib; mkdir -p tests/tkde2019/bin; mkdir -p tests/tkde2019/output; mkdir -p tests/vldbj2019/bin; mkdir -p tests/vldbj2019/ini; mkdir -p tests/vldbj2019/results; median/bin; mkdir -p median/output; mkdir -p tests/sspr2018/bin; mkdir -p tests/sspr2018/output; mkdir -p tests/unit_tests/bin; mkdir -p tests/unit_tests/output"
116  call(commands, shell=True)
117 
118 def build_external_libraries():
119  if os.path.isfile("ext/.INSTALLED"):
120  print("\n***** External libraries already installed. *****")
121  else:
122  print("\n***** Install external libraries. *****")
123  commands = "cd ext/fann.2.2.0; mkdir -p build; cd build; rm -rf *; cmake -DCMAKE_INSTALL_PREFIX=.. ..; make install; cd ..; rm -rf build"
124  call(commands, shell=True)
125  commands = "cd ext/nomad.3.8.1; mkdir -p lib; mkdir -p bin; cd src; make clean; make all; make clean; rm -rf ../bin"
126  call(commands, shell=True)
127  commands = "cd ext/libsvm.3.22; make lib; rm -f svm.o"
128  call(commands, shell=True)
129  f = open("ext/.INSTALLED", "w")
130  f.close()
131 
132 def determine_gurobi_version(gurobi_root):
133  if not os.path.isdir(gurobi_root):
134  raise Exception("Invalid argument \"" + gurobi_root + "\" for option gurobi: not a directory. Usage: python install.py [--gurobi <path-to-root-directory-of-Gurobi>] [...]")
135  gurobi_shared_lib = glob.glob(gurobi_root + "*/lib/libgurobi*.so")[0]
136  return gurobi_shared_lib[len(gurobi_shared_lib)-5:len(gurobi_shared_lib)-3]
137 
138 
139 def build_gedlib(args):
140  if not os.path.isdir(args.boost):
141  raise Exception("Invalid argument \"" + args.boost + "\" for option boost: not a directory. Usage: python install.py [--boost <path-to-directory-containing-Boost-sources>] [...]")
142  identifier = "gxl"
143  if args.lib and args.lib != "gxl":
144  identifier, node_id_type, node_label_type, edge_label_type = parse_custom_types(args.lib)
145  if identifier.lower() == "gxl":
146  raise Exception("Invalid argument \"" + args.lib + "\" for option lib. Usage: python install.py [--lib gxl|<indentifier-different-from-'gxl'>,<node-ID-type>,<node-label-type>,<edge-label-type>] [...]")
147  print("\n***** Modify sources for building user-defined shared library. *****")
148  create_template_instantiation(identifier, node_id_type, node_label_type, edge_label_type)
149  append_ged_env_hpp(identifier, node_id_type, node_label_type, edge_label_type)
150  append_cmake_lists(identifier)
151 
152  if args.clean:
153  print("\n***** Clean build directory. *****")
154  commands = "rm -rf build"
155  call(commands, shell=True)
156 
157  print("\n***** Goto build directory. *****")
158  commands = "mkdir -p build"
159  call(commands, shell=True)
160 
161  if (not os.path.isfile("build/Makefile")):
162  print("\n***** Run CMake. *****")
163  commands = "cd build; rm -rf *; cmake .. -DBOOST_ROOT=" + args.boost + " -DCMAKE_BUILD_TYPE="
164  if args.debug:
165  commands = commands + "Debug"
166  else:
167  commands = commands + "Release"
168  if args.gurobi:
169  commands = commands + " -DGUROBI_ROOT=" + args.gurobi + " -DGUROBI_VERSION=" + determine_gurobi_version(args.gurobi)
170  call(commands, shell=True)
171 
172  if args.doc:
173  print("\n***** Generate documentation. *****")
174  commands = "cd build; make doc"
175  call(commands, shell=True)
176 
177  if args.lib:
178  print("\n***** Build shared library. *****")
179  commands = "cd build; make " + identifier.lower() + "gedlib"
180  call(commands, shell=True)
181 
182  if args.tests:
183  print("\n***** Build test executables. *****")
184  if args.tests == "all":
185  commands = "cd build; make tests"
186  call(commands, shell=True)
187  else:
188  commands = "cd build; make " + args.tests
189  call(commands, shell=True)
190 
191  if args.median:
192  print("\n***** Build executable for median graph computation on LETTER graphs. *****")
193  commands = "cd build; make median_letter"
194  call(commands, shell=True)
195 
196 
197 print("**************************************************")
198 print(" GEDLIB 1.0 ")
199 print(" Installation Script ")
200 print("**************************************************")
201 
202 parser = argparse.ArgumentParser(description="Installs GEDLIB and its dependencies unless they have already been installed.", epilog="If called without arguments, only the dependencies are installed.")
203 parser.add_argument("--doc", help="build documentation; requires --boost <BOOST_ROOT>", action="store_true")
204 parser.add_argument("--lib", help="build shared library; requires --boost <BOOST_ROOT>", metavar="gxl|<indentifier>,<UserNodeID>,<UserNodeLabel>,<UserEdgeLabel>")
205 parser.add_argument("--tests", help="build test executables; requires --boost <BOOST_ROOT>", metavar="all|unit_tests|ged_env_tests|lsap_solver_tests|pr2018|sspr2018|vldbj2019|vldbj_train_ml|vldbj_test_lsape_based_methods|vldbj_test_lp_based_methods|vldbj_test_ls_based_methods|vldbj_test_misc_methods", choices=["all", "unit_tests", "ged_env_tests", "lsap_solver_tests", "pr2018", "sspr2018", "vldbj2019", "vldbj_train_ml", "vldbj_test_lsape_based_methods", "vldbj_test_lp_based_methods", "vldbj_test_ls_based_methods", "vldbj_test_misc_methods"])
206 parser.add_argument("--median", help="build binary for median graph computation on letter graphs", action="store_true")
207 parser.add_argument("--boost", metavar="<BOOST_ROOT>", help="specify path to directory containing Boost sources")
208 parser.add_argument("--gurobi", metavar="<GUROBI_ROOT>", help="specify path to directory containing Gurobi")
209 parser.add_argument("--debug", help="build in debug mode", action="store_true")
210 parser.add_argument("--clean", help="clean build directory and update makefile before build", action="store_true")
211 args = parser.parse_args()
212 if not args.boost and (args.lib or args.tests or args.doc):
213  raise Exception("The argument --boost BOOST is required if the script is called with one of the options --lib, --tests or --doc.")
214 build_external_libraries()
215 create_directories()
216 if args.lib or args.tests or args.doc or args.median:
217  build_gedlib(args)
218 print("\n***** Successfully installed GEDLIB. *****")