如何使用和构建 makefile 以 link scip 到 C?

How to use and build a makefile to link scip to C?

我是 C 的新手,我只需要使用 scip 中的一个函数。我制作了一个 make 文件如下:

SCIPDIR=$/Users/amin/Documents/cProgram/scipoptsuite-6.0.2/scip

include $(SCIPDIR)/make/make.project

%.o: %.c
    $(CC) $(FLAGS) $(OFLAGS) $(BINOFLAGS) $(CFLAGS) -c $<

all: cmain

cmain: cmain.o
    $(LINKCXX) cmain.o $(LINKCXXSCIPALL) $(LDFLAGS) $(LINKCXX_o) cmain

我的cmain.c文件是这样的:

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                                                                           */
/*                  This file is part of the program and library             */
/*         SCIP --- Solving Constraint Integer Programs                      */
/*                                                                           */
/*    Copyright (C) 2002-2019 Konrad-Zuse-Zentrum                            */
/*                            fuer Informationstechnik Berlin                */
/*                                                                           */
/*  SCIP is distributed under the terms of the ZIB Academic License.         */
/*                                                                           */
/*  You should have received a copy of the ZIB Academic License              */
/*  along with SCIP; see the file COPYING. If not visit scip.zib.de.         */
/*                                                                           */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**@file   GMI/src/cmain.c
 * @brief  main file for GMI cut example
 * @author Marc Pfetsch
 */

/*--+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/

#include <scip/scip.h>
#include <scip/scipdefplugins.h>

/** reads parameters */
static
SCIP_RETCODE readParams(
   SCIP*                 scip,               /**< SCIP data structure */
   const char*           filename            /**< parameter file name, or NULL */
   )
{
   if ( filename != NULL )
   {
      if ( SCIPfileExists(filename) )
      {
         SCIPinfoMessage(scip, NULL, "reading parameter file <%s> ...\n", filename);
         SCIP_CALL( SCIPreadParams(scip, filename) );
      }
      else
         SCIPinfoMessage(scip, NULL, "parameter file <%s> not found - using default parameters.\n", filename);
   }
   else if ( SCIPfileExists("scipgmi.set") )
   {
      SCIPinfoMessage(scip, NULL, "reading parameter file <scipgmi.set> ...\n");
      SCIP_CALL( SCIPreadParams(scip, "scipgmi.set") );
   }

   return SCIP_OKAY;
}

/** starts SCIP */
static
SCIP_RETCODE fromCommandLine(
   SCIP*                 scip,               /**< SCIP data structure */
   const char*           filename            /**< input file name */
   )
{
   /********************
    * Problem Creation *
    ********************/

   SCIPinfoMessage(scip, NULL, "read problem <%s> ...\n\n", filename);
   SCIP_CALL( SCIPreadProb(scip, filename, NULL) );

   /*******************
    * Problem Solving *
    *******************/

   /* solve problem */
   SCIPinfoMessage(scip, NULL, "solve problem ...\n\n");
   SCIP_CALL( SCIPsolve(scip) );

   SCIPinfoMessage(scip, NULL, "primal solution:\n");
   SCIP_CALL( SCIPprintBestSol(scip, NULL, FALSE) );

   /**************
    * Statistics *
    **************/

   SCIPinfoMessage(scip, NULL, "Statistics:\n");
   SCIP_CALL( SCIPprintStatistics(scip, NULL) );

   return SCIP_OKAY;
}

/** starts user interactive mode */
static
SCIP_RETCODE interactive(
   SCIP*                 scip                /**< SCIP data structure */
   )
{
   SCIP_CALL( SCIPstartInteraction(scip) );

   return SCIP_OKAY;
}

/** creates a SCIP instance with default plugins, evaluates command line parameters, runs SCIP appropriately,
 *  and frees the SCIP instance
 */
static
SCIP_RETCODE runSCIP(
   int                   argc,               /**< number of shell parameters */
   char**                argv                /**< array with shell parameters */
   )
{
   SCIP* scip = NULL;

   /*********
    * Setup *
    *********/

   /* initialize SCIP */
   SCIP_CALL( SCIPcreate(&scip) );

   /* we explicitly enable the use of a debug solution for this main SCIP instance */
   SCIPenableDebugSol(scip);

   /***********************
    * Version information *
    ***********************/

   SCIPprintVersion(scip, NULL);
   SCIPinfoMessage(scip, NULL, "\n");

   /* include default SCIP plugins */
   SCIP_CALL( SCIPincludeDefaultPlugins(scip) );

   /**************
    * Parameters *
    **************/

   if ( argc >= 3 )
   {
      SCIP_CALL( readParams(scip, argv[2]) );
   }
   else
   {
      SCIP_CALL( readParams(scip, NULL) );
   }

   /**************
    * Start SCIP *
    **************/

   if ( argc >= 2 )
   {
      SCIP_CALL( fromCommandLine(scip, argv[1]) );
   }
   else
   {
      SCIPinfoMessage(scip, NULL, "\n");

      SCIP_CALL( interactive(scip) );
   }

   /********************
    * Deinitialization *
    ********************/

   SCIP_CALL( SCIPfree(&scip) );

   BMScheckEmptyMemory();

   return SCIP_OKAY;
}

/** main method starting SCIP */
int main(
   int                   argc,               /**< number of arguments from the shell */
   char**                argv                /**< array of shell arguments */
   )
{
   SCIP_RETCODE retcode;

   retcode = runSCIP(argc, argv);
   if ( retcode != SCIP_OKAY )
   {
      SCIPprintError(retcode);
      return -1;
   }

   return 0;
}

现在在我有这 2 个文件的目录中,我 运行 Make 但它不起作用我得到错误:No such file or directory

make: *** No rule to make target `Users/amin/Documents/cProgram/scipoptsuite-6.0.2/scip/make/make.project'.  Stop.

我只是尝试按照某人建议的说明进行操作。如果可以,请你帮助我。我必须做什么?

你的做法不对。

第一个没有目标第一个食谱被调用,所以 all 目标应该在第一位。

第二:不要 include 其他文件并删除几乎所有内容,但目录变量和 all 目标

您只需添加 LD_FLAGS 变量,自动规则就会 link 为您服务。除非 scip 项目引入了一堆你需要的变量我不知道你为什么需要在这里包含它的 make 文件信息。

还需要注意的是,您加载到变量中的当前路径在赋值中的前导 $ 符号不正确,对于 link 我们需要确保其完整路径至 libscip.so(或 libscip.a)

LD_FLAGS+=-L${DIR_containing_libscip.so} -lscip

您可能还需要指向 header/include 个文件:

CPP_FLAGS+=-I${DIR_before_includes_of_scip}/include(如果它们被包含为 <scip/foo>。或者没有 /include 并且如果它们被包含为 <foo> 则进一步上升;这取决于根据项目风格。大多数项目使用 /include/projname 模式,以便将项目有效地保留在它自己的名称空间中,以便包含文件避免冲突。

假设其他所有内容都已构建并就位,并且我需要了解的 scip 没有什么特别之处...

您想将两件事分开

  1. 构建 SCIP
  2. 构建和链接您的程序。

构建 SCIP

通常人们会在大多数类 UNIX 系统上使用包管理器安装这个库,或者 make install 将它复制到系统中。然后,将自动找到头文件等。如果您不想这样做,而是 "bundle" SCIP 与您的程序一起使用,您通常会为您的程序分发该版本的副本或 link 该版本的副本(例如,源代码树中的代码副本. "external" 或使用 git 子模块,...)。不过无论如何,您不希望 SCIP 的路径是绝对的。 例如,使用此布局:

./
-- external/SCIP
-- cmain.c
-- Makefile

在 Makefile 中,您可以像这样设置 SCIPDIR 以备后用:

SCIPDIR := "./external/SCIP"

但是,首先,您应该了解如何手动构建。为此,您输入“./external/SCIP”并按照自述文件中的说明构建库(通常通过执行 ./configure && make && make install 之类的操作)。如果您想自动执行此操作,可以从 您的 主文件执行此操作。为此,您可以添加一个 "phony" 目标(即一个不会完全创建一个输出但会构建所有依赖项的目标),我们将其称为 dep:

dep:
        cd $(SCIPDIR); ./configure
        $(MAKE) -C $(SCIPDIR)

.PHONY: dep

(感谢@UpAndAdam 指出您必须在 运行 配置脚本之前更改 CWD)

为此,我们递归地为我们的子项目调用 make。我们不想在系统范围内安装文件,所以我们只构建库。

构建你的程序

我们现在添加了两个指定如何构建和 link C 程序的模式规则。 GNU/Make(您正在使用的那个)已经有内置的后缀规则 s.t。默认情况下它已经知道如何构建 C 程序,但是后缀规则很难处理并且您已经使用了其他 GNU/Make 功能,因此我们也可以使用大致等效的模式规则并禁用内置规则:

%.o: %.c
        $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

%: %.o
         $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $^ $(LDLIBS)

.SUFFIXES:

这里有个小提示:我们通过模式匹配从一个c文件编译一个目标文件。我使用了标准变量 CPPFLAGS(C 预处理器,而不是 C++!)、CFLAGS(C 编译器和功能标志)并在非选项参数 $< 之前列出了所有选项,它将保存列出的(第一个)依赖项,例如. "cmain.c"。并非所有 C 编译器都允许混合选项和参数。

对于 linking,我也这样做,但我列出了我们想要 link 最后的库。这很重要,如果列表中前面没有任何对象依赖于该变量,那么经典的 C 编译器将丢弃那里列出的所有库。

既然我们知道如何构建通用 C 程序,我们实际上想先构建 SCIP,然后再构建您的程序和 link 它。为此,我们将创建一个新的 PHONY 依赖项,称为 "all",它将完全做到这一点:

all: dep cmain

.PHONY: dep all

但是,如果我们现在执行 make all 它将失败,因为我们还没有指定包含路径等。为此,我们将之前使用的变量设置为所需的值(我猜到了具体的路径,因为我是在移动端):

CPPFLAGS += -I$(SCIPDIR)/include
LDFLAGS += -L$(SCIPDIR)
LDLIBS += -lscip

综合起来

现在这或多或少应该起作用了。不过有一件事是,通常将 all 作为默认目标,即 Makefile 中列出的第一个目标。所以我们写:

CPPFLAGS += -I$(SCIPDIR)/include
LDFLAGS += -L$(SCIPDIR)
LDLIBS += -lscip

all: dep cmain

%.o: %.c
    $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

%: %.o
    $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $^ $(LDLIBS)

dep:
    cd $(SCIPDIR); ./configure.sh
    $(MAKE) -C $(SCIPDIR)

.PHONY: dep all
.SUFFIXES:

注意:我在移动设备上,所以我无法测试也不知道确切的路径,但这应该可以指导您前进。同样出于同样的原因,我的代码在 Makefile 中使用空格而不是制表符。请务必更换它们。