/** external deps are manually set by the user
  * e.g. a static library linked to the project is an external dep (if set as such by the user)
  * so that a re-linking is forced if the static lib is updated
  */
bool DirectCommands::AreExternalDepsOutdated(ProjectBuildTarget* target,
                                             const wxString& buildOutput,
                                             wxArrayString*  filesMissing) const
{
    Compiler* compiler = CompilerFactory::GetCompiler(target->GetCompilerID());

    // if no output, probably a commands-only target; nothing to relink
    // but we have to check other dependencies
    time_t timeOutput = 0;
    if (!buildOutput.IsEmpty())
    {
        wxString output = buildOutput;
        Manager::Get()->GetMacrosManager()->ReplaceMacros(output);
        depsTimeStamp(output.mb_str(), &timeOutput);
        // if build output exists, check for updated static libraries
        if (timeOutput)
        {
            // look for static libraries in target/project library dirs
            wxArrayString libs = target->GetLinkLibs();
            const wxArrayString& prjLibs = target->GetParentProject()->GetLinkLibs();
            const wxArrayString& cmpLibs = compiler->GetLinkLibs();
            AppendArray(prjLibs, libs);
            AppendArray(cmpLibs, libs);

            const wxArrayString& prjLibDirs = target->GetParentProject()->GetLibDirs();
            const wxArrayString& cmpLibDirs = compiler->GetLibDirs();
            wxArrayString libDirs = target->GetLibDirs();
            AppendArray(prjLibDirs, libDirs);
            AppendArray(cmpLibDirs, libDirs);

            for (size_t i = 0; i < libs.GetCount(); ++i)
            {
                wxString lib = libs[i];

                // if user manually pointed to a library, without using the lib dirs,
                // then just check the file directly w/out involving the search dirs...
                if (lib.Contains(_T("/")) || lib.Contains(_T("\\")))
                {
                    Manager::Get()->GetMacrosManager()->ReplaceMacros(lib, target);
                    lib = UnixFilename(lib);
                    time_t timeExtDep;
                    depsTimeStamp(lib.mb_str(), &timeExtDep);
                    if (timeExtDep > timeOutput)
                    {
                        // force re-link
                        Manager::Get()->GetLogManager()->DebugLog(F(_T("Forcing re-link of '%s/%s' because '%s' is newer"),
                                                                        target->GetParentProject()->GetTitle().wx_str(),
                                                                        target->GetTitle().wx_str(),
                                                                        lib.wx_str()));
                        return true;
                    }
                    continue;
                }

                if (!lib.StartsWith(compiler->GetSwitches().libPrefix))
                    lib = compiler->GetSwitches().libPrefix + lib;
                if (!lib.EndsWith(_T(".") + compiler->GetSwitches().libExtension))
                    lib += _T(".") + compiler->GetSwitches().libExtension;

                for (size_t l = 0; l < libDirs.GetCount(); ++l)
                {
                    wxString dir = libDirs[l] + wxFILE_SEP_PATH + lib;
                    Manager::Get()->GetMacrosManager()->ReplaceMacros(dir, target);
                    dir = UnixFilename(dir);
                    time_t timeExtDep;
                    depsTimeStamp(dir.mb_str(), &timeExtDep);
                    if (timeExtDep > timeOutput)
                    {
                        // force re-link
                        Manager::Get()->GetLogManager()->DebugLog(F(_T("Forcing re-link of '%s/%s' because '%s' is newer"),
                                                                        target->GetParentProject()->GetTitle().wx_str(),
                                                                        target->GetTitle().wx_str(),
                                                                        dir.wx_str()));
                        return true;
                    }
                }
            }
        }
    }

    // array is separated by ;
    wxArrayString extDeps  = GetArrayFromString(target->GetExternalDeps(), _T(";"));
    wxArrayString addFiles = GetArrayFromString(target->GetAdditionalOutputFiles(), _T(";"));
    for (size_t i = 0; i < extDeps.GetCount(); ++i)
    {
        if (extDeps[i].IsEmpty())
            continue;

        Manager::Get()->GetMacrosManager()->ReplaceMacros(extDeps[i]);
        time_t timeExtDep;
        depsTimeStamp(extDeps[i].mb_str(), &timeExtDep);
        // if external dep doesn't exist, no need to relink
        // but we have to check other dependencies
        if (!timeExtDep)
        {
            if (filesMissing) filesMissing->Add(extDeps[i]);
            continue;
        }

        // let's check the additional output files
        for (size_t j = 0; j < addFiles.GetCount(); ++j)
        {
            if (addFiles[j].IsEmpty())
                continue;

            Manager::Get()->GetMacrosManager()->ReplaceMacros(addFiles[j]);
            time_t timeAddFile;
            depsTimeStamp(addFiles[j].mb_str(), &timeAddFile);
            // if additional file doesn't exist, we can skip it
            if (!timeAddFile)
            {
                if (filesMissing) filesMissing->Add(addFiles[j]);
                continue;
            }

            // if external dep is newer than additional file, relink
            if (timeExtDep > timeAddFile)
                return true;
        }

        // if no output, probably a commands-only target; nothing to relink
        // but we have to check other dependencies
        if (buildOutput.IsEmpty())
            continue;

        // now check the target's output
        // this is moved last because, for "commands only" targets,
        // it would return before we had a chance to check the
        // additional output files (above)

        // if build output doesn't exist, relink
        if (!timeOutput)
            return true;

        // if external dep is newer than build output, relink
        if (timeExtDep > timeOutput)
            return true;
    }
    return false; // no force relink
}