CellMLToSharedLibraryConverter.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "CellMLToSharedLibraryConverter.hpp"
00030
00031 #include <sstream>
00032 #include <unistd.h>
00033 #include <sys/stat.h>
00034 #include <ctime>
00035 #include <cstring>
00036 #include <cerrno>
00037
00038 #include "Exception.hpp"
00039 #include "ChasteBuildRoot.hpp"
00040 #include "PetscTools.hpp"
00041 #include "DynamicModelLoaderRegistry.hpp"
00042 #include "GetCurrentWorkingDirectory.hpp"
00043
00044 CellMLToSharedLibraryConverter::CellMLToSharedLibraryConverter(bool preserveGeneratedSources,
00045 std::string component)
00046 : mPreserveGeneratedSources(preserveGeneratedSources),
00047 mComponentName(component)
00048 {
00049 }
00050
00051 DynamicCellModelLoader* CellMLToSharedLibraryConverter::Convert(const FileFinder& rFilePath,
00052 bool isCollective)
00053 {
00054 DynamicCellModelLoader* p_loader;
00055 std::string absolute_path = rFilePath.GetAbsolutePath();
00056
00057 if (!rFilePath.Exists())
00058 {
00059 EXCEPTION("Dynamically loadable cell model '" + absolute_path + "' does not exist.");
00060 }
00061
00062 size_t dot_position = absolute_path.find_last_of(".");
00063 if (dot_position == std::string::npos)
00064 {
00065 EXCEPTION("File does not have an extension: " + absolute_path);
00066 }
00067 std::string extension = absolute_path.substr(dot_position+1);
00068 if (extension == "cellml")
00069 {
00070
00071 size_t slash_position = absolute_path.find_last_of("/\\");
00072 assert(slash_position != std::string::npos);
00073 std::string folder = absolute_path.substr(0, slash_position+1);
00074 std::string leaf = absolute_path.substr(slash_position+1, dot_position-slash_position);
00075 std::string so_path = folder + "lib" + leaf + "so";
00076
00077 FileFinder so_file(so_path, RelativeTo::Absolute);
00078 if (!so_file.Exists() || rFilePath.IsNewerThan(so_file))
00079 {
00080 if (!isCollective)
00081 {
00082 EXCEPTION("Unable to convert .cellml to .so unless called collectively, due to possible race conditions.");
00083 }
00084 ConvertCellmlToSo(absolute_path, folder, leaf);
00085 }
00086
00087 p_loader = DynamicModelLoaderRegistry::Instance()->GetLoader(so_file);
00088 }
00089 else if (extension == "so")
00090 {
00091
00092 p_loader = DynamicModelLoaderRegistry::Instance()->GetLoader(rFilePath);
00093 }
00094 else
00095 {
00096 EXCEPTION("Unsupported extension '." + extension + "' of file '" + absolute_path + "'; must be .so or .cellml");
00097 }
00098
00099 return p_loader;
00100 }
00101
00102 void CellMLToSharedLibraryConverter::ConvertCellmlToSo(const std::string& rCellmlFullPath,
00103 const std::string& rCellmlFolder,
00104 const std::string& rModelLeafName)
00105 {
00106 std::string tmp_folder, build_folder;
00107 std::string old_cwd = GetCurrentWorkingDirectory();
00108
00109 FileFinder chaste_root("", RelativeTo::ChasteSourceRoot);
00110 if (!chaste_root.IsDir())
00111 {
00112 EXCEPTION("No Chaste source tree found at '" << chaste_root.GetAbsolutePath()
00113 << "' - you need the source to use CellML models directly in Chaste.");
00114 }
00115 FileFinder component_dir(mComponentName, RelativeTo::ChasteSourceRoot);
00116 if (!component_dir.IsDir())
00117 {
00118 EXCEPTION("Unable to convert CellML model: required Chaste component '" << mComponentName
00119 << "' does not exist in '" << ChasteBuildRootDir() << "'.");
00120 }
00121
00122 try
00123 {
00124
00125 if (PetscTools::AmMaster())
00126 {
00127
00128 std::stringstream folder_name;
00129 folder_name << "dynamic/tmp_" << getpid() << "_" << time(NULL);
00130 tmp_folder = component_dir.GetAbsolutePath() + "/" + folder_name.str();
00131 build_folder = component_dir.GetAbsolutePath() + "/build/" + ChasteBuildDirName() + "/" + folder_name.str();
00132 int ret = mkdir(tmp_folder.c_str(), 0700);
00133 if (ret != 0)
00134 {
00135 EXCEPTION("Failed to create temporary folder '" << tmp_folder << "' for CellML conversion: "
00136 << strerror(errno));
00137 }
00138
00139 size_t dot_pos = rCellmlFullPath.rfind('.');
00140 std::string cellml_base = rCellmlFullPath.substr(0, dot_pos);
00141 EXPECT0(system, "cp " + cellml_base + "* " + tmp_folder);
00142
00143 std::string config_path = rCellmlFullPath.substr(0, rCellmlFullPath.length() - 7) + "-conf.xml";
00144 if (FileFinder(config_path, RelativeTo::Absolute).Exists())
00145 {
00146 EXPECT0(system, "cp " + config_path + " " + tmp_folder);
00147 }
00148
00149 EXPECT0(chdir, ChasteBuildRootDir());
00150
00151 EXPECT0(system, "scons --warn=no-all dyn_libs_only=1 build=" + ChasteBuildType() + " " + tmp_folder);
00152 EXCEPT_IF_NOT(FileFinder(tmp_folder + "/lib" + rModelLeafName + "so", RelativeTo::Absolute).Exists());
00153
00154 EXPECT0(chdir, old_cwd);
00155
00156 EXPECT0(system, "cp " + tmp_folder + "/lib" + rModelLeafName + "so " + rCellmlFolder);
00157 if (mPreserveGeneratedSources)
00158 {
00159
00160 EXPECT0(system, "cp " + build_folder + "/*.?pp " + rCellmlFolder);
00161 }
00162
00163 EXPECT0(system, "rm -r " + build_folder);
00164 EXPECT0(system, "rm -r " + tmp_folder);
00165 }
00166 }
00167 catch (Exception& e)
00168 {
00169 PetscTools::ReplicateException(true);
00170 if (FileFinder(tmp_folder, RelativeTo::Absolute).Exists())
00171 {
00172 if (mPreserveGeneratedSources)
00173 {
00174
00175 IGNORE_RET(system, "cp -r " + build_folder + " " + rCellmlFolder + "/build/");
00176 IGNORE_RET(system, "cp -r " + tmp_folder + " " + rCellmlFolder + "/tmp/");
00177 }
00178
00179 IGNORE_RET(system, "rm -rf " + build_folder);
00180 IGNORE_RET(system, "rm -r " + tmp_folder);
00181 }
00182 IGNORE_RET(chdir, old_cwd);
00183 EXCEPTION("Conversion of CellML to Chaste shared object failed. Error was: " + e.GetMessage());
00184 }
00185
00186
00187 PetscTools::ReplicateException(false);
00188 }
00189
00190 void CellMLToSharedLibraryConverter::CreateOptionsFile(const OutputFileHandler& rHandler,
00191 const std::string& rModelName,
00192 const std::vector<std::string>& rArgs,
00193 const std::string& rExtraXml)
00194 {
00195 if (PetscTools::AmMaster())
00196 {
00197 out_stream p_optfile = rHandler.OpenOutputFile(rModelName + "-conf.xml");
00198 (*p_optfile) << "<?xml version='1.0'?>" << std::endl
00199 << "<pycml_config>" << std::endl;
00200 if (!rArgs.empty())
00201 {
00202 (*p_optfile) << "<command_line_args>" << std::endl;
00203 for (unsigned i=0; i<rArgs.size(); i++)
00204 {
00205 (*p_optfile) << "<arg>" << rArgs[i] << "</arg>" << std::endl;
00206 }
00207 (*p_optfile) << "</command_line_args>" << std::endl;
00208 }
00209 (*p_optfile) << rExtraXml << "</pycml_config>" << std::endl;
00210 p_optfile->close();
00211 }
00212 PetscTools::Barrier("CellMLToSharedLibraryConverter::CreateOptionsFile");
00213 }